Você está na página 1de 56

Acessando Dispositivos Externos com Computadores Pessoais

Prof. Eduardo Augusto Bezerra <eduardob@inf.pucrs.br>


Faculdade de Informática, PUC-RS

Prof. Anderson R. Terroso <terroso@ee.pucrs.br>


Prof. Daniel Barros Jr. <dbarros@ee.pucrs.br>
Faculdade de Engenharia, PUC-RS

Porto Alegre, Junho de 2003

http://www.inf.pucrs.br/~eduardob/disciplinas/extensao/HW_SW_Interface

Objetivo:

Fornecer ao aluno conhecimento básico necessário para acessar dispositivos externos


conectados a uma porta de entrada/saída de um computador pessoal. Também é um
objetivo do curso mostrar como realizar esse acesso utilizando software livre.

Tópicos abordados:

1. Portas de entrada/saída
a. Visão geral
b. Porta paralela em detalhes (IEEE 1284)
c. Porta serial em detalhes (RS-232C)
d. Porta infrared em detalhes (IrDA)
e. Porta USB em detalhes

2. Gerência das portas de entrada/saída


a. Visão geral: sistemas operacionais e linguagens
b. Acesso às portas de entrada/saída usando a linguagem C/C++
c. Acesso às portas de entrada/saída usando a linguagem Java
d. Acesso às portas via rede e via internet (browser)

3. Interface software/hardware
a. Baixa potência (max 232, ‘245)
b. Interface de potência (transformador, relê, acoplador óptico, tip/bd)

4. Exemplos de aplicações (tentativa)


a. LEDs/switches (out/in, paralela)
b. Potenciômetro (in, paralela/serial)
c. Braço robô (out, serial)
d. RS-232C via rádio (in/out serial)
e. Leitora de código de barras e acionamento de tranca de porta

5. Prática

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 1
1. Portas de entrada/saída

a. Visão geral

• As portas de entrada/saída são a interface entre o processador (CPU) e outros


dispositivos de hardware internos ou externos ao computador pessoal;

• Portas de entrada/saída em um computador padrão IBM-PC possuem um


endereço entre 0 e 65.535:

• Os processadores 80(x)xx possuem duas instruções para acesso às portas: IN,


para transferência de dados da porta para o processador; e OUT, para
transferência de dados do processador para a porta endereçada;

• Essas instruções colocam o endereço da porta a ser acessada nos 16 bits menos
significativos do barramento de endereços, e os bits no barramento de dados são
enviados/recebidos para/da porta endereçada.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 2
• Um modem conectado à porta serial é um exemplo típico de utilização de portas
de entrada/saída para conexão de um computador à outro computador ou à
internet.

• A porta paralela pode ser utilizada para envio/recepção de bits em paralelo


para/de um dispositivo externo ao computador;

• As demais portas abordadas nesse curso (serial, infrared e USB), são utilizadas
para envio/recepção de bits serialmente para/de um dispositivo externo ao
computador;

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 3
• A porta serial e utilizada principalmente para comunicação de dados. Pode ser
utilizada tambem para acessar/controlar dispositivos conectados ao PC, mas
possui algumas desvantagens em relação a porta paralela.

• As duas grandes desvantagens são a necessidade de uma maior inteligência no


dispositivo a ser acessado, de forma a “falar” a mesma lingua (protocolo) do PC;
e a existencia de apenas dois fios para trafegar os dados, um para o envio e outro
para a recepção.

• Duas vantagens importantes são a padronização existente na porta serial, e a


possibilidade de uso de cabos mais longos do que na paralela.

• Com relação a comunicação de dados, a porta serial sempre foi o meio preferido
desde a introdução dos primeiros PCs. No passado havia apenas uma opção de
porta paralela, o padrão RS-232C, que sempre foi um gargalo com relação a
velocidade de transmissão de dados. Os PCs sempre processaram dados milhares
de vezes mais rapidamente do que o padrão RS-232C pode gerenciar.

• Novas tecnologias e padrões para comunicação serial resolvem um pouco esse


problema. Nesse curso são discutidos três padrões largamente utilizados: a porta
serial classica (RS-232C); a interface infra-vermelho (IrDA); e a porta USB
(Uníversal Serial Bus).

• Desde 1984, a porta RS-232C vem sendo utilizada como padrão em


microcomputadores pessoais tipo IBM-PC, e esse foi o único padrão para
comunicação serial em PCs ate bem recentemente.

• A interface IrDA forneceu ao RS-232C um novo meio para transmissão de sinais


via ar (wireless) no lugar dos tradicionais cabos.

• IrDA utiliza sinais infra-vermelho para transferência de arquivos entre PCs, sinais
esses identicos aos encontrados em um controle remoto de TV.

• A principal vantagem do IrDA e a ausencia de fios para conexão de dispositivos


(PCs, impressoras, notebooks, celulares, ...).

• A principal desvantagem e a baixa taxa de transferência, herdada do padrão RS-


232C. Porem isso nao chega a ser uma desvantagem para o tipo de acesso a
dispositivos tratado nesse curso.

• USB e no momento a melhor opção para comunicação serial. O padrão RS-232C


foi idealizado para conectar diretamente 2 dispositivos, ponto-a-ponto. Ja o USB

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 4
funciona como um verdadeiro barramento podendo conectar ate 127 dispositivos,
sem preocupações com diferentes pinagens de conectores e cabos. A velocidade
de transferência de dados e muitas vezes superior a do padrão RS-232C.

• A tabela a seguir apresenta uma comparação entre esses padrões para


comunicação serial.

Padrão Taxa de transmissão Meio Dispositivos por porta


RS-232C 115,200 bps Par trancado 1
IrDA 4 Mbps Otico 126
USB 12 Mbps Cabo especial com 4 fios 127

• Apesar das diferencas entre esses padrões, eles possuem uma caracteristica
comum que e a transferência de dados de forma uni-dimensional como uma fila
de bits.

b. Porta paralela em detalhes (IEEE 1284)

• Nos primeiros PCs a porta paralela era um recurso bastante utilizado para
conectar impressoras.

• Por ser bem mais rápida e simples de utilizar que a única outra porta padrão
existente na época, a serial RS-232, a porta paralela se tornou a preferida também
para acessar dispositivos externos e até mesmo para comunicação entre dois PCs.

• A porta paralela é ainda hoje a forma mais simples de acessar dispositivos


externos em um computador pessoal padrão IBM-PC.

• Infelizmente, com o passar dos anos, os engenheiros não satisfeitos com o padrão
existente, acabaram criando outros padrões para a porta paralela, e a característica
de simplicidade de utilização e instalação desse recurso se perdeu um pouco.

• Basicamente existem no mercado três padrões para conectores e quatro padrões


para funcionamento da porta paralela. Combinações dos três tipos de conectores
com os quatro tipos de padrões de funcionamento tambem existem.

• A confusão gerada por esses padrões e um grande responsavel pelos atrasos no


desenvolvimento de sistemas utilizando portas paralelas. Um sistema
desenvolvido para um determinado padrão pode vir a “quase” funcionar em um
PC que utiliza uma porta paralela “um pouco” diferente daquela onde o sistema
foi desenvolvido e testado.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 5
• Antes da definição do padrão IEEE 1284, as portas paralelas eram classificadas
em 4 tipos: Standard Parallel Port (SPP), Enhanced Parallel Port (EPP),
Extended Capabilities Ports (ECP) e Bi-directional Parallel Ports (ou PS-2).

• A maioria dos computadores modernos utiliza ECP, que consegue emular


protocolos antigos.

• Esse padrão possibilita tambem utilização da porta de forma bi-direcional, o que


nao era possível nos primeiros padrões existentes. Essa caracteristica bi-
direcional tornou a porta paralela uma forma bastante simples e eficiente para
acesso a dispositivos externos.

• As figuras a seguir mostram a pinagem de uma porta paralela e conector quando


utilizada para envio de dados para uma impressora, e tambem os pinos a serem
conectados para a transferência de dados entre dois computadores.

• Dos 25 pinos existentes no conector, 17 são utilizados para transferência de dados


e controle, e os 8 restantes para aterramento.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 6
• A tabela a seguir mostra a pinagem do conector de acordo com o padrão IEEE
1284-A (existem ainda os padrões B e C), em todos os modos de operação.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 7
Pin Compatibility mode Nibble mode Byte mode EPP mode ECP mode
1 nStrobe HostClk HostClk nWrite HostClk
2 Data 1 Data 1 Data 1 AD1 Data 1
3 Data 2 Data 2 Data 2 AD2 Data 2
4 Data 3 Data 3 Data 3 AD3 Data 3
5 Data 4 Data 4 Data 4 AD4 Data 4
6 Data 5 Data 5 Data 5 AD5 Data 5
7 Data 6 Data 6 Data 6 AD6 Data 6
8 Data 7 Data 7 Data 7 AD7 Data 7
9 Data 8 Data 8 Data 8 AD8 Data8
10 nAck PtrClk PtrClk Intr PeriphClk
11 Busy PtrBusy PtrBusy nWait PeriphAck
12 Perror AckDataReq AckDataReq User def. 1 nAckReverse
13 Select Xflag Xflag User def. 3 Xflag
14 nAutoFd HostBusy HostBusy nDStrb HostAck
15 nFault nDataAvail nDataAvail User def. 2 nPeriphRequest
16 nInit nInit nInt nInt nReverseRequest
17 nSelectIn 1284 Active 1284 Active nAStrb 1284 Active
18 Pin 1 (nStrobe) ground
return
19 Pins 2 and 3 (Data 1 and
2) ground return
20 Pins 4 and 5 (Data 3 and
4) ground return
21 Pins 6 and 7 (Data 5 and
6) ground return
22 Pins 8 and 9 (Data 7 and
8) ground return
23 Pins 11 and 15 ground
return
24 Pins 10, 12, and13
ground return
25 Pins 14, 16, and 17
ground return

• Um problema fisico em um cabo paralelo e a interação entre os fios. As


transições bruscas nos sinais trafegando nos fios causam interferencia no sinal
Quanto mais longo o cabo, maior a degradação. Um comprimento máximo
recomendavel para um cabo paralelo e de 10 metros.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 8
• Cada porta paralela em um PC possui um endereço base único. No PC original,
IBM utilizou os endereços 03BCH, 0378H e 0278H. Esses endereços foram
mantidos e utilizados ate hoje.

• Esses endereços base são normalmente ocultados do programador, e os


programas e sistemas operacionais, normalmente, utilizam os labels LPT1, LPT2
e LPT3. O label PRN e associado a porta LPT1.

• Os labels são atribuidos as portas paralelas pelo sistema no momento da


inicialização (boot). Uma rotina na BIOS do PC procura as portas paralelas em
cada um dos três endereços pre-definidos na ordem utilizada acima. A primeira
porta encontrada recebe o label LPT1, e assim sucessivamente. Por exemplo,
caso nao exista nenhuma porta nos endereços 03BCH e 0378H, o label LPT1 será
associado a porta no endereço 0278H (se existir uma porta nesse endereço).

• Cada porta paralela possui um conjunto de três registradores utilizados na sua


operação. O primeiro registrador, localizado no endereço base da porta, e
utilizado para armazenar dados (recebidos ou enviados). Trata-se do Registrador
de Dados.

• Cada um dos 8 bits desse registrador esta ligado a cada um dos 8 pinos de dados
do conector da porta paralela para interface com o mundo exterior. A
correspondencia e direta: o bit mais significativo do registrador esta conectado ao
bit mais significativo do conector.

• Quando o microprocessador (ex. Pentium) escreve um dado no endereço base de


uma das portas paralelas (ex. 0378H), o registrador mantêm esse valor
internamente (no registrador) e externamente (nos pinos do conector), ate que um
novo dado seja escrito pelo microprocessador.

• O segundo registrador de uma porta paralela e utilizado pelo PC para monitorar o


que esta acontecendo no conector. Trata-se do Registrador de Status.

• Os 5 bits mais significativos correspondem aos sinais que aparecem no conector


da porta paralela. Na sua utilização original (impressão), o bit 7 indica a condição
de impressora ocupada; o bit 6 ACK; o bit 5 indica falta de papel; bit 4 indica
select; e o bit 3 indica erro. Os três bits menos significativos nao possuiam
nenhuma função em especial na porta paralela do PC original.

• Se o endereço base da porta paralela e o 0378H, por exemplo, entao o


Registrador de Status estara no endereço 0379H.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 9
• O terceiro registrador (endereço 037AH para endereço base 0378H), e utilizado
no PC original para envio de comandos para a impressora. O Registrador de
Controle de Impressora envia comandos utilizando seus 5 bits menos
significativos.

• O bit 4 desse registrador e de algum interesse para acionamento de dispositivos


externos, pois pode ser utilizado na geração de interrupções. Colocando esse bit
em 1 faz com que o dispositivo possa gerar uma interrupção disparada pelo sinal
ACK no Registrador de Status. Ao receber essa interrupção o microprocessador,
dependendo da configuração do sistema, poderá interromper um processamento
para atender os eventos na porta paralela.

• O padrão EPP introduz 5 novos registradores aos 3 existentes. Esses registradores


estao localizados nos 5 endereços seguintes aos 3 utilizados pelos registradores
convencionais. Esses novos registradores nao são descritos pois os 3
registradores convencionais são suficientes, no contexto desse curso, para acessos
aos dispositivos externos.

• O padrão ECP tambem introduz um novo esquema que permite o endereçamento


de ate 128 dispositivos conectados a porta paralela. Quando o PC deseja enviar
dados para um determinado dispositivo, um comando e enviado para a porta
paralela, contendo o endereço do dispositivo desejado. Quando um dispositivo
padrão ECP recebe o comando, o endereço recebido e comparado com seu
proprio endereço, ignorando o dado recebido no caso dos endereços serem
diferentes.

• A seguir um resumo dos dados necessarios para a utilização da porta paralela


para acesso a dispositivos externos.

Pinagem da porta paralela (femea):

13 12 11 10 9 8 7 6 5 4 3 2 1
25 24 23 22 21 20 19 18 17 16 15 14

Pino 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Função C0 D0 D1 D2 D3 D4 D5 D6 D7 S6 S7 S5 S4 C1 S3 C2 C3

S = Registrador de Status, D = Registrador de Dados, C = Registrador de Controle


Os pinos 18 a 25 são terra (GND)

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 10
Registrador de Controle (end. Base + 1):

Pino Hexadecimal Função


1 0x01 Strobe
14 0x02 Autofeed
16 0x04 Init
17 0x08 SelectIn
* 0x10 Inten
* 0x20 Direction

Registrador de Status (end. Base + 2):

Pino Hexadecimal Função


* 0x04 nIRQ
15 0x08 nError
13 0x10 Select
12 0x20 PaperOut
10 0x40 nACK
11 0x80 nBusy

* Registradores de controle internos

c. Porta serial em detalhes (RS-232C)

• O padrão RS-232C define diversos parametros para a comunicação serial, entre


eles os níveis de tensão que representam o 0 e o 1 lógicos, os conectores a serem
utilizados (formato e numero de pinos), e o formato dos dados a serem utilizados.

• Com relação a portabilidade, a existencia do padrão RS-232C simplifica a vida


do desenvolvedor de aplicações que utilizam a porta serial. A porta paralela e
bem mais simples de se utilizar do ponto de vista do desenvolvedor, porem a
diversidade de padrões pode fazer com que uma aplicação nao funcione em
qualquer maquina.

• Uma vez identificada a porta paralela em uso, e o padrão utilizado, o


desenvolvedor nao precisa se preocupar em implementar nenhum protocolo
especial para acionar ou receber informações do dispositivo externo. Todos os
dados trafegados pela porta paralela ficarão armazenados (“bufferizados”) no
registrador de dados da porta.

• Ja em uma porta serial existe um módulo responsavel pela gerencia da


comunicação, e o dispositivo externo devera “falar” a mesma lingua desse
módulo de comunicação serial.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 11
• No caso dos computadores padrão IBM-PC, o módulo responsavel pela gerencia
da porta paralela e implementado com um circuito integrado baseado no Intel
8250.

• O 8250 implementa uma UART (Uníversal Asynchronous Receiver/Transmitter)


que, basicamente, se encarrega de serializar os bytes recebidos (conversão
paralelo para serial), adiconar os bits de controle definidos no protocolo RS-232C
(start bit, stop bit e paridade), e enviar os bits um a um para o pino de transmissão
do conector.

• O 8250 realiza tambem a função inversa, ou seja, receber os bits serialmente,


remover os bits de controle, remontar o byte recebido e disponibilizar esse byte
no registrador de dados do 8250.

• A UART 8250 passou a fazer parte dos computadores padrão IBM-PC em 1981.
Esse dispositivo possui capacidade de armazenamento para apenas um byte e nao
e o mais adequado, por exemplo, para comunicação utilizando os modems da
epoca com velocidade mais rapida que esse dispositivo podia gerenciar. Nesse
caso caracteres recebidos em uma comunicação podiam ser perdidos.

• Para solucionar esse problema, a partir de 1984 os computadores pessoais


passaram a utilizar a UART 16450 que e uma versão melhorada da 8250. Essa
nova UART tambem possui apenas um byte para armazenamento dos dados
recebidos, mas o circuito interno e bem mais rapido do que o da 8250, resolvendo
o problema de perda de dados para os modems da epoca.

• Com a utilização de sistemas multi-tarefas, em algumas situações os PCs


passaram a nao ter tempo para ler o byte recebido na UART antes que um novo
bate chegasse. O PC podia estar ocupado realizando alguma outra tarefa e um
novo byte recebido na porta serial iria sobrepor o byte pronto para ser lido antes
do PC o faze-lo.

• Em 1987 os PCs passaram a utilizar a UART 16550A com capacidade de


armazenamento para mais do que um byte recebido, e posteriormente a UART
166550 que possui uma FIFO com capacidade para armazenar ate 16 bytes
recebidos. Essa fila e uma boa solucap para armazenar os dados recebidos de
modems de alta velocidade em ambientes multi-tarefa.

• As UARTs utilizadas nos PCs atuais são compativeis com a 166550, porem são
encapsuladas em dispositivos do tipo ASIC (Application Specific Integrated
Circuit) ficando dificil sua identificação visual na placa do computador.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 12
• Devido a utilização do padrão RS-232C, e possível interfacear um dispositivo
externo a um IBM-PC via porta serial, bastando para isso incluir um 8250, ou
qualquer outra UART compativel com esse padrão, no projeto do dispositivo.

• A tabela a seguir apresenta a pinagem de conectores de 9 (DB-9) e 25 (DB-25)


pinos de acordo com o padrão Rs-232C. A maioria dos computadores atuais
utilizam o conector de 9 pinos.

25-pinos (DB-25) 9-pinos (DB-9) Simbolo Função


2 3 Tx Transmite dados
3 2 Rx Recebe dados
4 7 RTS Permissão para envio
5 8 CTS Permissão fornecida
6 6 DSR Dado pronto
7 5 GND Terra
8 1 CD Deteção de portadora
20 4 DTR Terminal pronto
22 9 RI Indicador de Ring

• No projeto da interface para conexão a um dispositivo a ser controlado via porta


serial, bastam 3 pinos (3 fios): pino 5 – Terra, pino 3 – transmissão de dados,
pino 2 – recepção de dados. A figura a seguir mostra como ficaria o cabo serial
com os devidos conectores para conectar um PC a um dispositivo externo.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 13
PC DB-9 macho DB-9 macho dispositivo
DB-9 femea DB-9 femea

Tx 3 -------> 3 Tx -------> Rx 2 ---> 2 Rx


Rx 2 <------- 2 Rx <------- Tx 3 <---- 3 Tx
GND 5 -------- 5 GND -------- GND 5 ------ 5 GND

• Uma observação importante e quanto aos níveis de tensão do padrão RS232-C.


Para possibilitar a utilização de cabos mais longos evitando perdas no sinal, os
níveis lógicos 0 e 1 são representados por +15V e –15V respectivamente. Assim,
esses são os níveis de tensão trafegando nos fios no diagrama acima.

• A UART 8250 trabalha com níveis de tensão TTL (0V para 0 lógico, e +5V para
1 lógico), e e preciso utilizar um conversor de níveis de tensão para realizar a
transformação de 0V para +15V, e de +5V para –15V, e vice-versa. Para isso e
utilizado o circuito integrado MAX232.

• O diagrama de blocos mostrando os registradores da UART 8250 e apresentado


abaixo:

• A 8250 necessita estar conectada a um dispositivo mestre de forma a ser


programada sua forma de operação. Esse dispositivo mestre, que no caso dos PCs
e a CPU (ex. Pentium), precisa programar a UART para trabalhar em uma certa

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 14
velocidade de transferência de dados, com uma determinado tamanho de palavra
de dados, um determinado numero de stop bits, e uma determinada paridade. Os
mesmos parametros devem ser utilizados para programar a UART em utilização
do outro lado da linha. Caso alguma dessas informações esteja diferente em um
dos dois lados, nao haverá comunicação pois as duas UARTs estarão utilizando
protocolos diferentes.

• A figura a seguir mostra o envio da letra ‘A’ em uma UART programada para
uma palavra de tamanho 8 bits, com 1 stop bit, paridade impar e com uma
velocidade de 300 bps. Como a letra ‘A’ na tabela ASCII possui 2 bits em 1 e os
demais em 0, o bit de paridade esta em 1 de forma a gerar um numero impar de
bits em 1.

• A seguir são descritos funcionalmente os registradores da 8250.

Registrador de dados:

Registrador de Recepção: Ao se realizar uma leitura na 8250, obtem-se o byte


contido nesse registrador proveniente da conversão de serial para
paralelo dos bits de entrada (pino Rx).
Registrador de transmissão: Uma operação de escrita carrega um byte nesse
registrador para ser convertido de paralelo para serial pela 8250, e
posterior transmissão pelo pino Tx).

Status:

Registrador de Status de Linha: utilizado para indicar condições de operação


da linha.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 15
7 6 5 4 3 2 1 0
0 TxE TBE Break Erro de Erro de Erro de RxRdy
framming paridade overrun

Bit 0: 1 = existe byte pronto para ser lido no registrador de recepção.


Bit 1: 1 = um byte no registrador de recepção foi sobre escrito por um novo byte. 0
primeiro byte foi perdido.
Bit 2: 1 = erro de paridade.
Bit 3: 1 = stop bit invalido
Bit 4: 1 = interface detecta a linha em zero durante um tempo maior que a duração
de um byte assincrono.
Bit 5: Buffer de transmissão vazio. 1 = um byte e movido do buffer de transmissão
para o registro de deslocamento, onde o byte e transmitido serialmente.
Bit 6: Transmissor vazio. 1 = registro de deslocamento vazio.

Registrador de Status do Modem: utilizado para indicar o status do modem.

7 6 5 4 3 2 1 0
DCD RI DSR CTS ∆ DCD ∆ RI ∆ DSR ∆ CTS

Bits 0 – 3: 1 = ocorreu uma mudanca no respectivo pino desde a ultima leitura na


porta.
Bit 4 - 7: indica o status dos pinos da porta.

Registrador de Identificação de Interrupção: Apos uma interrupção, o bit 0


recebe 0, e os bits 1 e 2 determinam a fonte da interrupção.

Bit 2 Bit 1 Bit 0 Identificador


0 0 1 Sem interrupção
1 1 0 Condição de erro
1 0 0 Byte recebido
0 1 0 Buffer de transmissão vazio
0 0 0 Mudanca na entrada da porta serial

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 16
Controle:

Registrador de Controle de Linha: utilizado para formatação dos dados.

7 6 5 4 3 2 1 0

DLAB Break Paridade Stop bit Bits de dados

Bits 0 - 1 : quantidade de bits por caracter. 00 = 5 bits


01 = 6 bits
10 = 7 bits
11 = 8 bits

Bit 2 : quantidade de bits por caracter. 0 = 1 stop bit


1 = 2 stop bits

Obs. Se a quantidade de bits por caracter for igual a 5, o numero de stop bits será
automaticamente 1 ½ stop bits.

Bits 3 - 5 : determinam a paridade. 000 = sem paridade


001 = paridade impar
011 = paridade par
101 = marca (mark)
111 = espaco (space)

Bit 6 : 1 = saida Tx vai para o nível lógico 0.

Bit 7 : 1 = registro de transmissão recebe o byte de menor ordem (LSB) da


taxa de transmissão e o registro de controle de interrupção recebe o byte de
maior ordem (MSB).

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 17
Registrador de Controle de Interrupção: utilizado para habilitar os quatro tipos
de interrupção do 8250.

7 6 5 4 3 2 1 0
0 0 0 0 Pinos de Erro na TBE RxRdy
entrada recepção

Bit 0: 1 = uma interrupção e gerada quando um byte estiver disponível no registrador


de recepção.
Bit 1: 1 = uma interrupção e gerada quando a 8250 puder receber um novo byte para
trasnmissão.
Bit 2: 1 = uma interrupção e gerada quando ocorrer um erro de paridade, overrun
(sobre escrita) ou stop bit.
Bit 3: 1 = uma interrupção e gerada quando qualquer entrada da porta serial mudar
de estado.

Registrador de Controle do Modem

7 6 5 4 3 2 1 0
0 0 0 Loop GP02 GP01 RTS DTR

Bit 0: 1 = ativa a saida DTR.


Bit 1: 1 = ativa a saida RTS.
Bit 2: Saida definida pelo usuário. Normalmente em 0.
Bit 3: Saida definida pelo usuário. Normalmente em 0.

• Finalmente, para programar a taxa de transferencia (velocidade da comunicacao),


e preciso utilizar o bit 7 (DLAB) do Registrador de Controle de Linha, em
conjunto com o Registradores de Controle de Interrupcao e com o Registrador de
Dados, da seguinte forma:

1. Colocar o bit DLAB em 1 para indicar que a parte baixa (LSB) da


programacao velocidade sera colocada no Registrador de Dados, e a parte alta
(MSB) no Registrador de Controle de Interrupcao.
2. Escrever no Registrador de Controle de Interrupcao o valor desejado de
acordo com a tabela a seguir (00H para 9600bps, por exemplo).
3. Escrever no Registrador de Dados o valor desejado de acordo com a tabela a
seguir (0CH para 9600bps, por exemplo).

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 18
velocidade Divisor MSB Divisor (LSB)
Divisor (Dec)
(bps) Reg. Contr. Interrupcao Reg. Dados
50 2304 09h 00h
300 384 01h 80h
600 192 00h C0h
2400 48 00h 30h
4800 24 00h 18h
9600 12 00h 0Ch
19200 6 00h 06h
38400 3 00h 03h
57600 2 00h 02h
115200 1 00h 01h

Endereços da UART 8250 (porta COM1):

Dados (escrita/leitura) 03F8H


Registrador de Controle de Interrupção 03F9H
Registrador de Identificação de Interrupção 03FAH
Registrador de Controle de linha 03FBH
Registrador de Controle do Modem 03FCH
Registrador de Status da Linha 03FDH
Registrador de Status do Modem 03FEH

Obs. A COM2 inicia no endereço 02F8H, a COM3 no endereço 03E8H e a COM4


no endereço 02E8H.

• O funcionamento da troca de dados assincrona entre duas UARTs e relativamente


simples. No lado do transmissor o pino de envio de dados Tx permanece em nivel
logico 1 ate existir um caracter pronto para transmissao. Nesse instante o pino e
colocado em zero, representando o start bit. Os bits de dados sao enviados logo
apos o start bit, um apos o outro. Um bit de paridade, opcionalmente, segue os
bits de dados. Apos isso um ou mais stop bits sao enviados. O bit de paridade e a
soma dos bits de dados e indica se o dado contaim um numero impar ou par de
bits 1. Para paridade par esse bit sera 0. Para paridade impar o bit sera 1.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 19
d. Portas infrared (infra-vermelho)

• O padrão para comunicação via infra-vermelho foi definido em 1993 por um


grupo com cerca de 120 integrantes auto-denominado InfraredDevelopers
Association (IrDA).

• O objetivo inicial era a definição de um padrão para conectar notebooks a


desktops sem a necessidade de cabos. Rapidamente o padrão passou a ser
utilizado por diversos fabricantes para a conexão de notebooks a periféricos tais
como impressoras, mice, teclados e modems (em telefones celulares, por
exemplo).

• A primeira versão foi totalmente baseada no padrão RS-232C, apenas


substituindo os cabos por uma interface optica. As velocidades de comunicação
são as mesmas, variando de 2.400 a 115.200 bits por segundo.

• Comparando com a tecnologia de radio, tambem utilizada para conexão wireless,


infra-vermelho necessita menos espaco pois utiliza apenas um LED no lugar de
uma antena (que tambem possui um preco bem mais elevado). Projetos com
infravermelho nao causam interferencias em radios, televisões, marca-passos e
dispositivos avionicos.

• Uma desvantagem seria a faixa de infra-vermelho que e mais limitada que a do


radio, por exemplo, e restrita a apenas um angulo reto visual entre os dois
dispositivos. A separação máxima entre dispositivos precisa ser em torno de 1
metro, com algumas implementações podendo chegar a 2 metros de distancia.
Essa restrição pode se tornar uma vantagem em projetos onde seguranca e
privacidade dos dados são caracteristicas importantes.

• A luz infra-vermelha e basicamente radiação eletromagnetica invisivel, pois


possui um comprimento de onda mais longo que o da luz visivel. A visão humana
consegue ver luz com comprimento de onda entre 400 angstroms (violeta intenso)
e 700 angstroms (vermelho escuro). Radiação infra-vermelho vai de 700
angstroms ate 1000 angstroms ou mais. O padrão IrDA define que o sinal infra-
vermelho utilizado em computadores pessoais possui um comprimento de onda
entre 850 e 900 angstroms. O sistema IrDA tambem concentra esse sinal em um
feixe infra-vermelho conico com dispersão de no máximo 30 graus.

• As portas IrDA precisam, obrigatoriamente, operar a uma velocidade base de


9600 bps. Todas as demais velocidades são opcionais.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 20
• O padrão IrDA permite o uso de todas as velocidades convencionais em portas
seriais a partir de 2.400 bps a 115.200 bps, utilizando o padrão de modulação
RZI. O padrão IrDA de alta velocidade (IrDA v. 1.1) possui três velocidades
adicionais: 576 Kbps; 1,152 Mbps e 4,0 Mbps.

• Independentemente da faixa de velocidades implementada em um sistema, os


dispositivos IrDA primeiro estabelecem a comunicação na velocidade obrigatoria
de 9.600 bps. Assim que os dois dispositivos estabelecem a velocidade a ser
utilizada na comunicação, ambos chaveiam para esse modo e realizam a
comunicação na velocidade acordada.

• A celula infra-vermelha de um transmissor envia os dados em pulsos. De forma


diferente dos sinais (bits) trafegando no interior de um computador pessoal, que
normalmente permanecem constantes durante um pulso de clock, os pulsos IrDA
duram apenas uma fração do pulso de clock. O espacamento relativamente
grande entre pulsos torna mais facil para o receptor optico distinguir esses pulsos.

• Em velocidades de ate 115.200 bps, cada pulso infra-vermelho precisa durar pelo
menos 1,41 microsegundos. Cada pulso IrDA dura apenas 3/16 do comprimento
de um bit com uma tolerancia de 10% para mais. Por exemplo, cada bit de um
sinal de 9.600 bps dura 104,2 microsegundos (um segundo dividido por 9600).
Um pulso IrDA tipico, nessa velocidade de 9.600 bps, dura 3/16 desse tempo, ou
seja, 19,53 microsegundos.

• O sistema IrDA nao trabalha com dados a nível de bits. Os dados transmitidos
são trabalhados a nível de pacotes (o nome utilizado no padrão IrDA e frames).
Um frame IrDA pode possuir de 5 a 2050 bytes ou mais. Assim como em outros
sistemas baseados em pacotes, um frame IrDA possui informação de endereço,
dados, e correção de erros (aplicada a nível de frame). O formato do frame esta
bem definido do padrão IrDA.

• Para o controle de dispositivos utilizando a interface IrDA, e preciso que ambos


os lados possuam os diodos laser para emissão e recepção dos sinais infra-
vermelho, o circuito necessario para converter os sinais para bits, e a
implementação do protocolo para realizar a construção/identificação dos pacotes
IrDA.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 21
e. Porta USB

• Existem duas desvantagens principais na utilização de portas seriais em geral:


baixa velocidade e numero limitado de portas em uma maquina. USB resolve
esses dois problemas com uma velocidade em torno de 12 Mbits/seg, e um
numero quase ilimitado de conexões. O padrão suporta tambem baixas
velocidades com uma taxa na ordem de 1,5 Mbits/seg.

• O padrão USB foi introduzido em 1996 e e visto como o sucessor natural do RS-
232C conectando a maioria, senao quase todos, os periféricos existentes. O
padrão e utilizado para conectar de forma simples desde teclados ate caixas
registradoras.

• A complexidade das pinagens (sinais) existente nos padrões para comunicação


serial e resolvida no padrão USB por intermedio de camadas de software. O
padrão USB gerencia, em software, toda a complexidade da conexão de multiplos
dispositivos com diferentes velocidades.

• USB classifica o hardware serial em dois tipos: hubs e funções. Um hub USB
possui “tomadas” nas quais podem ser conectadas funções. Uma função USB e o
dispositivo (periférico) propriamente dito.

• O meio USB funciona como um barramento permitindo a conexão de diversos


periféricos a uma mesma porta USB no computador pessoal. Todos os periféricos
compartilham exatamente o mesmo sinal.

• A informação trafega no barramento na forma de pacotes, e todas as funções


(periféricos) recebem todos os pacotes. O computador pessoal acessa funções
individuais por meio da inclusão de endereços nos pacotes. Apenas a função
endereçada utiliza o pacote enviado.

• O projeto do padrão USB permite a utilização de hubs de forma hierarquica, com


hubs conectados a hubs que são conectados a hubs e assim por diante,
funcionando como uma estrutura de arvore, como mostrado na figura a seguir.

• O computador pessoal e o hub base para o sistema USB e e denominado host. O


software/hardware no computador pessoal que controla o hub e todo o sistema
USB e denominado “controlador do barramento”. Cada sistema USB possui
apenas um controlador de barramento.

• A parte mais complexa do sistema e o software que implementa o protocolo


USB. Esse software se encarrega de gerenciar toda a arvore de hubs e funções,

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 22
que e construida de forma simples bastando utilizar as regras para conexão
ilustradas na figura anterior. Nao existe um limite para o numero de hubs a serem
utilizados, porem existe um numero máximo de 127 funções a serem utilizadas
em um sistema (arvore) USB. Esse limite e imposto pelos 7 bits utilizados no
endereçamento das funções (um endereço e reservado).

• Outro limite e o comprimento de no máximo 5 metros que um cabo USB pode ter
para conectar uma função a um barramento. Porem, como hubs podem fortalecer
o sinal, um sistema USB pode se prolongar por grandes distancias ao se utilizar
diversos hubs.

• Como parte do processo plug-and-play, o controlador USB realiza uma caça a


dispositivos na inicialização do computador pessoal. Cada dispositivo USB
conectado ao barramento e interrogado e um mapa e construido localizando cada
dispositivo por hub e endereço da porta. Essa informação se torna parte do
endereçamento.

• Devido ao uso desse sistema de endereçamento, cada dispositivo USB precisa ter
um software basico para entender o protocolo. No computador pessoal, cada
função precisa ter um driver, normalmente em software, responsavel por gerar os
comandos ou pacotes de dados para o dispositivo associado.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 23
• Um driver USB funciona como um provedor de servicos, fornecendo o canal
(pipe) para roteamento dos dados para as diversas funções. Consequentemente,
para cada dispositivo USB adicionado ao barramento e necessario a instalação do
driver (software).

• Os cabos USB possuem em uma ponta conectores do tipo A e na outra ponta


conectores do tipo B. Isso evita ligações incorretas, uma vez que todas as portas
A são saidas e todas as portas B são entradas.

• Os cabos possuem 4 fios. Um para alimentação (5 Volts), um terra (GND), e dois


para os dados. O fio de alimentação permite o fornecimento de tensão para o
dispositivo periférico. Os dois fios de dados são trancados e conduzem os dados
na forma de um sinal digital diferencial, ou seja, possuem um sinal de magnitude
igual, porem de polaridade invertida. Isso e utilizado de forma que quando os
dois sinais são subtraidos o resultado cancela qualquer ruido que venha a
aparecer nos fios.

• Os fios de dados são verde (sinal positivo D+ na figura abaixo) e branco (sinal
negativo D- na figura abaixo). A alimentação e o fio vermelho, e o terra o fio
preto.

• Como o forte do padrão USB e o protocolo implementado em software, e como


chips decodificadores USB (ex. Cypress SL811HS) são de preco bastante
acessivel podendo ser facilmente adicionados ao dispositivo periférico a ser
conectado ao barramento, a codificação dos sinais nos fios nao e apresentada
aqui. O mais importante e um bom entendimento do protocolo USB de forma a
facilitar a escrita do driver para o novo dispositivo.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 24
• O protocolo USB e baseado em pacotes. Todas as mensagens trocadas
necessitam de três pacotes. Uma troca de mensagens inicia com o host enviando
um pacote tocken. O pacote tocken possui o endereço do dispositivo desejado e
tambem informação de controle descrevendo a natureza da mensagem.
Dependendo da natureza da operação, o host ou o dispositivo envia o pacote de
dados. Apesar desse nome, o pacote de dados poderá estar vazio, sem nenhuma
imformação. A troca de dados finaliza com o recebimento de um pacote ACK
que informa o recebimento do pacote de dados. Um quarto tipo de pacote,
denominado pacote Especial, e utilizado para funções adicionais.

• Todos os pacotes iniciam com dois componentes de um byte cada: um campo de


sincronismo (Sync) e uma identificação.

• O campo de sincronismo gera uma rajada de bits no barramento USB fazendo


com que todos os dispositivos conectados resetem seus relogios e sincronizem
com o host. Esse campo aparece no barramento codificado como três pulsos
on/off seguidos por uma marca de largura de dois bits.

• O byte identificador do pacote contem quatro bits que definem a natureza do


pacote, e quatro bits utilizados para confirmar a validade dos quatro primeiros
bits. Os quatro bits de verificação são o complemento de um dos quatro primeiros
bits. Os quatro bits de identificação possibilitam a definição de 16 tipos
diferentes de pacotes. Os dois bits mais significativos especificam um entre
quatro tipos de pacotes. Os dois bits menos significativos sub-dividem a categoria
do pacote. A tabela a seguir lista o pacote de identificação dos quatro tipos
basicos de pacotes USB.

Byte identificador Tipo do pacote


XX00XX11 Especial
XX01XX10 Token
XX10XX01 Handshake (ACK)
XX11XX00 Dados

• Apenas o host envia pacotes do tipo token. Esses pacotes possuem quatro bytes,
e se divide em cinco partes, conforme mostrado na figura a seguir.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 25
• Os dois primeiros bytes seguem o padrão de todos os pacotes USB. O primeiro
byte e um campo de sincronismo que marca o inicio dos bits do token. O segundo
byte e a identificação do pacote (PID).

• O PID define quatro tipos de pacotes token: pacote de saida que envia dados do
host para o dispositivo; pacote de entrada que recebe dados no host proveniente
de um dispositivo; pacote de configuração (setup) que endereça um dispositivo
especifico; e um pacote de inicio de frame, que ajuda na sincronização do
sistema. A tabela a seguir mostra PIDs e respectivos tipos de pacote token.

Byte de identificação de pacote (PID) Tipo de pacote token


00011110 Saida
01011010 Inicio de Frame (SOF)
10010110 Entrada
11010010 Configuração (setup)

• Para pacotes token “Entrada”, “Saida” e “Setup”, os sete bits que seguem o PID
representam o campo de endereço, que identifica o dispositivo para o qual o host
deseja comandar ou enviar dados. Quatro bits adicionais fornecem um codigo
Endpoint. Um Endpoint e uma seção endereçavel individualmente de uma função
USB, que possibilita que projetistas de hardware possam separar um dispositivo
fisico em diversas unidades logicas. Por exemplo, um teclado com um mouse
embutido pode ter um endereço geral para atuar como um dispositivo USB único.
Atribuindo Endpoints individuais ao teclado e ao mouse, possibilita que os
projetistas possam endereçar individualmente cada componente do teclado.

• Pacotes token do tipo inicio de frame (SOF) diferem de outros pacotes USB uma
vez que eles são do tipo broadcast. Todos os dispositivos do sistema recebem e
decodificam esses pacotes, mas nao retornam um ACK referente a eles. Os 11
bits que deveriam ser os campos de endereço e Endpoint indicam um numero do
frame.

• O host envia um pacote token do tipo SOF a cada milisegundo definindo o incio
do frame USB denominado one-millisecond.

• O host atribui numeros de frames de forma incremental, iniciando com zero e


adicionando um a cada frame sucessivo. Quando essa contagem atinge o valor
máximo de 3072 (11 bits), a mesma e iniciada novamente em zero. A figura a
seguir mostra a representação grafica de um pacote token do tipo SOF.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 26
• Todos os pacotes token possuem no final cinco bits de codigo CRC (Cyclic
Redundacy Check). O CRC fornece uma forma de verificar a integridade do
campo de endereçamento e Endpoint. O CRC nao cobre o PID, que possui o sua
propria correção de erro embutida.

• Os pacotes de dados são os responsaveis pela transmissão da informação em


sistemas USB. Um pacote de dados, assim como todos os demais pacotes USB,
inicia com um campo de sincronismo de um byte, seguido por um pacote de
identificação.

• O dado propriamente dito segue em uma sequencia de tamanho entre 0 e 1,023


bytes. Um campo de CRC de dois bytes e utilizado para verificar a integridade do
campo de dados. O campo PID possui um mecanismo proprio para verificação da
sua integridade. A figura a seguir mostra a representação grafica de um pacote de
dados USB.

• O campo PID define dois tipos de pacotes de dados, Dados 0 e Dados 1.


Funcionalmente, contudo, os dois tipos de dados e consequentemente o PID,
formam um sistema de verificação de erros adicional entre o transmissor e o
receptor. O transmissor altera entre Dados 0 e Dados 1 para indicar que recebeu
um ACK valido referente ao pacote de dados anterior. A tabela a seguir lista
esses tipos de pacotes de dados.

Identificação do pacote Tipo do pacote de dados


00110011 Dados 0
10110010 Dados 1

• Por exemplo, o transmissor envia um pacote de dados do tipo Dados 0. Apos o


receptor ter decodificado esse pacote com sucesso, ele envia um sinal de
confirmação para o transmissor na forma de um pacote de ACK. Se o transmissor
receber e decodificar o pacote de ACK com sucesso, o proximo pacote de dados

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 27
que ele enviara será Dados 1. A partir dessa troca no tipo do pacote de dados, o
receptor sabera que o seu ACK foi recebido com sucesso.

• Pacotes ACK possuem um tamanho de dois bytes, consistindo de um campo de


sincronismo e um pacote de identificação. A figura a seguir mostra um pacote de
ACK do padrão USB, e a tabela seguinte lista as três formas desse tipo de pacote.

Byte de identificação do pacote Tipo de ACK


00101101 ACK
01011010 NAK
11100001 STALL

2. Gerencia das portas de entrada/saída

a. Visão geral: sistemas operacionais e linguagens

• Até recentemente sistemas operacionais como o MS-DOS rodando em


processadores tais como o 8088 (PC-XT) e 80286 (primeiro PC-AT) permitiam
ao desenvolvedor re-programar praticamente toda a máquina. Era possível, por
exemplo, re-programar o teclado ou o relógio de tempo real do computador. Isso
se devia ao fato também da arquitetura desses processadores que não possuíam
características tais como o modo protegido dos processadores atuais.

• Com o surgimento de processadores mais sofisticados e com a disseminação e


evolução do sistema operacional MS-Windows para uma plataforma multitarefa
32 bits, e em modo protegido, o acesso direto ao hardware passou a ser um perigo
para o bom funcionamento do sistema. Processadores ‘386 e superiores possuem
o “modo protegido” onde o acesso direto a portas pode ser impedido.

• Existem duas solucoes para o problema de acesso as portas de entrada e saida nas
versoes 32 bits do Windows. A primeira solucao e a criacao de um device driver
que executara com privilegio nivel 0 para entrada/saida (modo kernel, ou super-
usuario). Dados poderao entao ser enviados por programas do usuario (privilegio
nivel 3) para o device driver, e o driver executara a operacao de entrada/saida.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 28
• Uma outra alternativa e a modificacao da tabela de permissoes de entrada/saida
do sistema operacional. Existe um bit nessa tabela para cada porta do sistema. A
tabela podera ser modificada de forma a dar permissao de acesso irrestrito a uma
determinada porta. A opcao do device driver e a melhor. O driver devera ser
escrito de forma a verificar se existem conflitos antes de acessar a porta.

• O conceito de drivers (device drivers) foi introduzido no Windows com o


objetivo de isolar o hardware da aplicacao do usuario. As versões mais recentes
do Windows possuem o conceito de drivers virtuais de dispositivos, ou VxDs,
que possibilitam ao desenvolvedor escrever aplicativos que acessem virtualmente
os recursos de entrada/saída e interrupções desse sistema operacional.

• Um driver é utilizado, basicamente, para interfacear um dispositivo de hardware à


CPU. Sistemas operacionais de 32 bits tais como o Windows NT, Windows XP e
Unix, proíbem ou tentam evitar que os aplicativos acessem diretamente as portas
de entrada e saída. É preciso utilizar os serviços dos drivers, que possuem os
devidos previlégios, para obter acesso indireto às portas de entrada/saída.

• A forma mais bem comportada e, consequentemente, a mais indicada para


acessar um dispositivo externo, é por intermédio da API (Application
Programming Interface) apropriada.

• É possível, por exemplo, escrever um driver USB utilizando diretamente as


informações sobre o protocolo descrito anteriormente para gerenciar um
dispositivo conectado a essa porta de um computador pessoal. Porém é muito
mais fácil utilizar as funções disponíveis na API da linguagem escolhida para a
implementação. Essas funcoes se encarregam de “conversar” com o driver.

• A utilização das funções da API na construção do driver ou aplicação significa


não apenas uma economia nas etapas de implementação e teste, mas também uma
maior portabilidade.

• Outro ponto é a questão de segurança existente em sistemas unix e versões


recentes do Windows. Como os programas de usuários comuns (sem permissões
de super-usuário) normalmente não conseguem acessar diretamente as portas de
entrada/saída da máquina, o uso de algumas APIs pode possibilitar ao usuário o
acesso em mais alto nível da porta, ou melhor, do driver para acesso à porta.

• Para as portas que não possuem um padrão bem definido, é mais difícil de se
encontrar APIs padronizadas, e o usuário acaba tendo que utilizar o
conhecimento mais baixo nível sobre a porta para implementar o driver ou
aplicação.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 29
• O sistema de entrada/saída do unix possui uma estrutura conhecida como open-
read-write-close, uma vez que esses são os passos para a realização de uma
operação de E/S com arquivos, dispositivos ou portas de E/S.

• As operações de entrada/saída são realizadas por meio de arquivos. O sistema


operacional atribui um descritor de arquivo, que é um número que identifica o
arquivo, tanto para dispositivos, portas de E/S ou arquivos propriamente ditos.
Um programa utiliza esse descritor de arquivo para acessar o “arquivo”.

• Uma função de abertura de arquivo (open) é necessária para atribuir o descritor à


variável no programa. Uma função de leitura (read) é utilizada para transferir
informações do “arquivo” para o programa do usuário. Uma função de escrita
(write) é utilizada para transferir informações do programa do usuário para o
“arquivo”. Uma função de fechamento de arquivo (open) é utilizada para
devolver o descritor do arquivo ao sistema operacional. As funções de
leitura/escrita utilizam o número do descritor do arquivo, o número de bytes a ser
transferido, e o endereço de um buffer para o qual serão escritos ou lidos dados.

• Nas próximas seções são apresentados trechos de programa para acessar as portas
de entrada/saída de um computador pessoal, utilizando tanto as instruções para
acesso direto do processador (in e out), quanto as interrupções da BIOS e do
DOS, e também o acesso via descritores de arquivos e APIs. Serão apresentados
exemplos de acesso às portas paralela e serial (RS-232C), pois existe
disponibilidade no laboratório de dispositivos externos que utilizam essas
portas/protocolos.

b. Acesso às portas de entrada/saída usando a linguagem C/C++

• Nessa seção é utilizada a abordagem botton-up na apresentação dos exemplos de


programa nas linguagens C e C++ para acesso às portas serial (RS-232C) e
paralela de um computador pessoal.

Porta Serial RS-232C


acesso direto ao hardware – inportb, outportb
linguagem C – MS-DOS/Windows 9x

• O primeiro exemplo, listado a seguir, usa a porta serial via acesso direto ao
hardware do computador, e os exemplos seguintes utilizam recursos de mais alto
nível como, por exemplo, interrupções e chamadas de sistema (function call). O
sistema operacional e compilador utilizados estão identificados nos comentários
no início do programa.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 30
Obs. Uma chamada de sistema é uma rotina implementada em software, fazendo
parte do sistema operacional ou como um driver, que é utilizada pelo sistema
operacional ou pela aplicação para acesso ao hardware. Uma chamada de
sistema pode solicitar uma interrupção, que por sua vez é originada no
firmware do computador pessoal, ou fornecida pelo driver em software. A
função tanto da chamada de sistema quanto da interrupção é a mesma, ou seja,
chegar na interface a nível de hardware e utilizar características específicas
dessa porta de entrada e saída.
1
2 /*
3 serial_io.c
4
5 Programa em C para gerencia da porta serial RS-232C utilizando acesso direto
6 ao hardware pelas instrucoes in e out.
7
8 Eduardo Augusto Bezerra, Maio de 2003
9
10 compilador Turbo C++ versao 1.0 (Borland)
11 */
12 #include <stdio.h>
13 #include <dos.h>
14 #include <process.h>
15 #include <conio.h>
16 #define end_ctrl_50 0x03FD /* Enderecos da UART 8250 */
17 #define end_dado_50 0x03F8
18 #define LRC 0x03FB
19 #define MSB 0x03F9
20 #define LSB 0x03F8
21 #define MCR 0x03FC
22 #define LSR 0x03FD
23 #define MSR 0x03FE
24 #define IOR 0x03F8
25 #define IIR 0x03FA
26 #define IER 0x03F9
27
28 void inic8250(){ /* inicializacao da 8250 */
29 outportb(LRC, 0x80); /* DLAB = 1, programa velocidade em MSB e LSB */
30 outportb(MSB, 0x00);
31 outportb(LSB, 0x0C); /* 00H 0CH == 9600 bps */
32 outportb(LRC, 0x07); /* 8 bits de dados, 1 stop bit, sem paridade */
33 }
34
35 void reseta8250(){ /* reseta a 8250 */
36 inportb(LSR);
37 inportb(MSR);
38 inportb(IOR);
39 inportb(IIR);
40 }
41
42 void enable8250(){ /* habilita a 8250 */
43 outportb(IER, 0x01);
44 }
45
46 void disable8250(){ /* desabilita interrupcoes da 8250 */
47 outportb(IER, 0x00);
48 }
49
50 void transm_dado(unsigned char caracter){ /* transmite um caracter */
51 while (!(32 & inportb(end_ctrl_50)) == 32);
52 outportb(end_dado_50, caracter);
53 }

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 31
54
55 unsigned char status(){ /* Le status da 8250 */
56 return (inportb(end_ctrl_50) & 0x01);
57 }
58
59 int main(){
60 int opcao = 0;
61 unsigned char caracter = '';
62 unsigned char aux = '';
63
64 inic8250();
65 reseta8250();
66 outportb(IER, 0x00); /* sem interrupcoes */
67 while (opcao != 4){
68 clrscr();
69 printf("Entre com:\n");
70 printf("\t\t\t1 - Transmitir um caracter pela serial\n");
71 printf("\t\t\t2 - Receber um caracter pela serial\n");
72 printf("\t\t\t3 - Transmitir arquivo pela serial\n");
73 printf("\t\t\t4 - Sair do programa\n");
74 opcao = getch() - '0';
75 caracter = '';
76 /* transmissao de um caracter */
77 if (opcao == 1)
78 while (caracter != 0x1B){ /* repete ate' pressionar ESC */
79 disable8250();
80 printf("\nEntre com o carcter a ser transmitido ... ");
81 caracter = getch();
82 printf("%c", caracter);
83 transm_dado(caracter); /* envia um caracter */
84 }
85 /* recepcao de um caracter */
86 if (opcao == 2){
87 printf("\n\nAguardando caracter na porta serial ... ");
88 for (;;){
89 while(!status()) if (kbhit()) break;
90 if (kbhit() && getch()) break;
91 aux = inportb(end_dado_50); /* recebe um caracter */
92 printf("\nRecebido o caracter --> %c", aux);
93 }
94 }
95 /* transmissao de arquivo */
96 if (opcao == 3){
97 FILE *fp;
98 char arq[20];
99 printf("\n\nNome do arquivo: "); gets(arq);
100 if (!(fp = fopen(arq, "r"))){
101 printf("\nArquivo nao existe!");
102 exit(-1);
103 }
104 while(!feof(fp)){ /* transmite arquivo */
105 caracter = fgetc(fp);
106 disable8250();
107 transm_dado(caracter);
108 if (status()) putch(inportb(end_dado_50));
109 }
110 fclose(fp);
111 printf("\nPressione qualquer tecla para o menu.");
112 while(!kbhit());
113 }
114 }
115 return 0;
116 }

• A função outportb (int porta, unsigned char valor); envia para o endereço
especificado em porta um byte especificado em valor. A função inportb (int

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 32
porta); le um byte de um endereço especificado em porta. Com essas duas
funcoes é possível acessar todos os registradores da 8250, enviando palavras de
controle para sua programação, bem como enviando e recebendo bytes da
interface RS-232C. Os endereços utilizados no programa acima foram discutidos
na seção 1 (portas de entrada/saida, porta serial RS-232C em detalhes).

Porta Serial RS-232C


Uso de interrupcoes – int 14H
linguagem C – MS-DOS/Windows 9x

• Uma outra forma de acessar a UART 8250 é por intermédio dos serviços da
ROM-BIOS (interrupção 14H da BIOS), listados na tabela a seguir:

INT 14H Entrada Saida


1 Inicializa parametros da AL = parametro AX = status da porta
porta serial AH = 00
DX = nr. da porta.
2 Transmite um caracter AL = caracter
AH = 01 AH = status: passa/falha
DX = nr. da porta
3 Recebe um caracter AH = 02 AH = status: passa/falha
DX = nr. da porta AL = caracter
4 Obtem status da porta serial AH = 03 AH = codigo de status
DX = nr. da porta

Inicialização – AL: 7 6 5 4 3 2 1 0

Bits 0 .. 1 : tamanho da palavra 10 = 7 bits


11 = 8 bits

Bit 2 : stop bits 0 = 1 stop bit


1 = 2 stop bits

Bits 3 .. 4 : paridade 00, 10 = sem paridade


01 = paridade impar

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 33
11 = paridade par

Bits 5 .. 7 : taxa de transferencia 000 = 110 bps


001 = 150 bps
010 = 300 bps
011 = 600 bps
100 = 1200 bps
101 = 2400 bps
110 = 4800 bps
111 = 9600 bps

• No exemplo a seguir a 8250 é programada para transferências a 9600 bps, 1 stop


bit, 8 bits de dados e sem paridade.

1 /*
2 serial_bios.c
3
4 Programa em C para gerencia da porta serial RS-232C
5 utilizando a INT 14H da BIOS.
6
7 Eduardo Augusto Bezerra
8 Maio de 2003
9
10 compilador Turbo C++ versao 1.0 (Borland)
11 */
12 #include <stdio.h>
13 #include <dos.h>
14 #include <conio.h>
15 #define SERIAL 0x14
16 #define ESC 0x1B
17
18 int main(){
19 union REGS r;
20 unsigned char caracter = '';
21 /* 7654321 */
22 r.h.ah = 0x000; /* 11100011 9600 bps, */
23 r.h.al = 0x0E3; /* = 8 bits de dados, */
24 r.x.dx = 0x000; /* E3H 1 stop bit, */
25 int86(SERIAL, &r, &r); /* sem paridade */
26
27 while (caracter != ESC) {
28 printf ("\nEntre com o caracter: ");
29 caracter = getch();
30 printf("%c", caracter);
31 r.h.ah = 1; /* AH = 1, transmite caracter */
32 r.h.al = caracter;
33 r.x.dx = 0;
34 int86(SERIAL, &r, &r); /* Transmite o caracter */
35 }
36 return 0;
37 }

• A função int int86(int nr. interrupção, union REGS *inregs, union REGS
*outregs); realiza um pedido de interrupção para a CPU. Essa segunda forma é
bem mais simples do que o acesso direto à 8250 mostrado anteriormente.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 34
Porta Serial RS-232C
acesso direto ao hardware – inb, outb
linguagem C – Linux

• A listagem do programa para Linux a seguir apresenta uma versao resumida do


codigo listado anteriormente para utilizacao da porta serial, via acesso direto ao
hardware.
1 /*
2 serial_io.c
3
4 Programa em C para gerencia da porta serial RS-232C
5 utilizando acesso direto ao hardware pelas instrucoes
6 in e out.
7
8 Eduardo Augusto Bezerra
9 Maio de 2003
10
11 compilador gcc version 3.2 20020903 (Red Hat Linux 8.0 3.2-7)
12 */
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <sys/io.h>
16 #include <unistd.h>
17 #include <malloc.h>
18 #include <string.h>
19
20 #define end_ctrl_50 0x03FD /* Enderecos da UART 8250 */
21 #define end_dado_50 0x03F8
22 #define LRC 0x03FB
23 #define MSB 0x03F9
24 #define LSB 0x03F8
25 #define MCR 0x03FC
26 #define LSR 0x03FD
27 #define MSR 0x03FE
28 #define IOR 0x03F8
29 #define IIR 0x03FA
30 #define IER 0x03F9
31
32 int main(){
33 unsigned char caracter = ' ';
34 int a;
35 a = setuid(0);
36 printf("setuid = %d\n", a);
37 if (ioperm(end_dado_50, 2, 1)) {
38 perror("ioperm");
39 printf("Erro: Nao liberou a porta serial!");
40 }
41 /* inicializacao da 8250 */
42 outb(0x80, LRC); /* 8 bits de dados */
43 outb(0x00, MSB); /* 1 stop bit */
44 outb(0x0C, LSB); /* sem paridade */
45 outb(0x07, LRC);
46 /* reseta a 8250 */
47 inb(LSR); inb(MSR); inb(IOR); inb(IIR);
48 outb(0x00, IER); /* sem interrupcoes */
49 caracter = ' ';
50 /* transmissao de um caracter */
51 while (caracter != 0x1B){ /* repete ate' pressionar ESC */

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 35
52 printf("\nEntre com o caracter a ser transmitido ... ");
53 scanf("%c", &caracter);
54 printf("%c", caracter);
55 outb(caracter, end_dado_50); /* envia um caracter */
56 }
57 return 0;
58 }

• Alguns comentarios sobre o programa acima e o uso da porta serial no Linux.


• A porta serial RS-232C nao pode ser acessada diretamente por usuarios comuns.
Apenas usuarios pertencente ao grupo uucp possuem acesso a essa porta. Uma
solucao e desenvolver uma aplicacao ou driver que seja executado, por exemplo,
em background como um daemon, e que responda a chamadas de sistema
realizadas por programas dos usuarios. Essa aplicacao devera ser disparada por
um usuario do grupo uucp de preferencia na inicializacao do sistema.
• A solucao utilizada para o exemplo listado anteriormente, foi a criacao de um
usuario especial pertencente ao grupo uucp, e a execucao do programa realizada
por esse usuario.
• Como o programa utiliza acesso direto ao hardware via instrucoes inb e outb,
apenas usuarios pertencentes ao grupo root possuem permissao para executar
esse programa. Uma solucao para possibilitar a execucao por usuarios comuns
(no caso o usuario pertencente ao grupo uucp), foi a utilizacao da funcao setuid
na linha 35. Essa funcao altera a identidade do processo atual (process ID) para o
valor passado como argumento. No caso o valor 0 informa ao Linux que o
processo pertence ao root. Nesse caso um usuario root tera que compilar o
programa, e logo a seguir alterar as permissoes do arquivo para 4755 (chmod
4755 nome_do_arquivo_executavel). Isso possibilitara que um usuario comum
execute o programa com funcoes para acesso direto ao hardware.

• A funcao ioperm na linha 37 e utilizada para fornecer acesso a portas para


usuarios que nao possui privilegios de root (ver man ioperm para maiores
informacoes).

Porta Serial RS-232C


Acesso via descritores de arquivos – open/read/write/close
linguagem C++ – Linux

• A listagem a seguir apresenta a implementacao para as funcoes membro da classe


RobotLinux, utilizada para controlar o braco robo que e um dos exemplos
utilizados no curso. O computador pessoal se comunica com o circuito de
controle do braco robo via porta serial RS-232C.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 36
1 /************************************************************
2 * File RobotLinux.cpp - Implementation for the RobotLinux class
3 *
4 * This class has the implementation for virtual
5 * methods from Robot.h (and Robot.cpp)
6 *
7 * Project: Fischer Arm
8 *
9 * Author: Eduardo Augusto Bezerra
10 * Date: 04/04/2003
11 *
12 * Last change: Eduardo Augusto Bezerra
13 * Date: 26/04/2003
14 *
15 * Methods for controlling the robot in C++ under linux
16 * This code has been tested on linux Red Hat 8.0
17 *
18 *************************************************************/
19
20 #include "RobotLinux.h"
21
22 /************************************************************
23 * Constructor
24 *************************************************************/
25 RobotLinux::RobotLinux(void){
26 motorWord = 0;
27 fd = -1;
28 }
29 /************************************************************
30 * Destructor
31 *************************************************************/
32 RobotLinux::~RobotLinux(void){
33 close(fd);
34 }
35
36 /************************************************************
37 * void RobotLinux::openSerial(int ser)
38 *
39 * open the serial connection;
40 * sets the serial parameters to 9600 Baud, no parity, 8, 1;
41 * and turns all motors off
42 *
43 *************************************************************/
44 void RobotLinux::openSerial(int ser){
45 // serial names
46 const char *com1="/dev/ttyS0", *com2="/dev/ttyS1",
47 *com3="/dev/ttyS2", *com4="/dev/ttyS3";
48
49 struct termios options;
50
51 switch(ser) {
52 case 1: strcpy(serial,com1);
53 break;
54 case 2: strcpy(serial,com2);
55 break;
56 case 3: strcpy(serial,com3);
57 break;
58 case 4: strcpy(serial,com4);
59 break;
60 default: cout << "Error! valid ports are 1, 2, 3 and 4. "
61 << "Will try to open port 1." << endl;
62 }
63
64 fd = open(serial, O_RDWR|O_NOCTTY|O_NDELAY);
65 if (fd == -1) // ERROR!!

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 37
66 cout << "Error opening " << serial << endl;
67 else
68 fcntl(fd, F_SETFL, 0);
69 cout << "Serial port in use: " << serial << endl << endl;
70
71 // Program serial port to 9600, 8, 1, no parity
72 //
73
74 // Get the current options for the port
75 tcgetattr(fd, &options);
76
77 // Set the baud rate to 9600
78 cfsetispeed(&options, B9600);
79 cfsetospeed(&options, B9600);
80
81 // Enable the receiver and set local mode
82 options.c_cflag |= (CLOCAL | CREAD);
83
84 // Setting parity checking (no parity) 8N1
85 options.c_cflag &= ~PARENB; /* no parity */
86 options.c_cflag &= ~CSTOPB; /* 1 stop bit */
87 options.c_cflag &= ~CSIZE; /* Mask the character size bits */
88 options.c_cflag |= CS8; /* Select 8 data bits */
89
90 // Setting raw input
91 options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
92
93 // Setting raw output
94 options.c_oflag &= ~OPOST;
95
96 // Set the new options for the port
97 tcsetattr(fd, TCSANOW, &options);
98
99 motorsOff(); // motors off
100 }
101
102 /************************************************************
103 * char sendCommand(char motorWord)
104 *
105 * gets a full word representing all inputs (1..8)
106 *************************************************************/
107 char RobotLinux::sendCommand(char motorWord){
108
109 char commandWord[2];
110 commandWord[0] = '\xc1'; // 1st byte: 193 in hexadecimal
111 commandWord[1] = motorWord; // 2nd byte: motorWord
112 int i;
113
114 if (fd == -1)
115 cout << "Erro: the serial port is closed. Please, "
116 << "use the openSerial() method to open it. " << endl;
117 else{
118 int n = write(fd, commandWord, 2); // send 2 bytes command & motors
119 if (n < 0)
120 cout << "Error! write() command and motor bytes failed." << endl;
121 else {
122 fcntl(fd, F_SETFL, FNDELAY);
123 i = read(fd, commandWord, 1); // read 1 Byte interface status
124 fcntl(fd, F_SETFL, 0);
125 commandWord[1] = 0; /* set end of string, so we can printf */
126 }
127 }
128 return commandWord[0];
129 }

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 38
• De forma semelhante ao exemplo de acesso direto ao hardware, a solucao
utilizada no caso da aplicacao para controle do braco robo foi a criacao de um
usuario especial pertencente ao grupo uucp, e a execucao dos programas para
acesso a serial (ao braco robo) realizada por esse usuario.

• No programa anterior, nas linhas 46 e 47 estao listados os nomes dos arquivos


que identificam as portas seriais com1 a com 4 no Linux. Esses nomes substituem
os antigos /dev/cua0 a /dev/cua3.
• Uma das portas (1, 2, 3 ou 4) e aberta na linha 64, de acordo com a selecao do
usuario. O flag O_RDWR faz com que a porta seja aberta para entrada e saida. O
flag O_NOCTTY garante que o programa nao sera o “terminal em controle” da
porta. Se esse flag nao for utilizado, outras entradas de dados (ex. ^C enviado
pelo teclado) pode afetar o programa. O flag O_NDELAY avisa ao Linux que o
programa ira ignorar o sinal DCD da RS-232C. Se esse flag nao for utilizado, o
processo ficara desativado ate que o outro lado da comunicacao ative o pino DCD
(coloque 0 nesse pino).

• A funcao fcntl na linha 68 e utilizada para configurar a porta serial para possiveis
operacoes de leitura. O flag F_SETFL e utilizado em conjunto com o terceiro
argumento para ativar ou desativar o modo de leitura da porta. Ao se utilizar 0
como terceiro argumento na funcao fcntl, uma operacao de leitura na porta serial
(read) ira bloquear a execucao do programa ate que um carcter seja recebido, um
intervalo de tempo expire, ou um erro ocorra. Para realizar leituras nao
bloqueantes na serial, utlizar o flag FNDELAY, no lugar do 0.

• A funcao tcgetattr na linha 75 e utilizada para ler os parametros associados ao


descritor de arquivo fd (no caso a porta serial aberta), e armazena-los na variavel
options. Esses dados correspondem ao status atual da porta serial.

• Logo a seguir, na linha 78, a funcao cfsetispeed e utilizada para programar a porta
serial para velocidade de recepcao de 9600 bps. Na linha seguinte a funcao
cfsetospeed e utilizada para programar a porta serial para velocidade de
transmissao de 9600 bps.

• Nas linhas seguintes os demais parametros para a comunicacao serial sao


armazenados no registro options. A porta serial do braco robo esta configurada
para comunicacao a 9600 bps, com 8 bits de dados, 1 stop bit e sem paridade.

• A funcao tcsetattr na linha 97 realiza a escrita do registro options, programando


assim a UART do computador pessoal de acordo com os dados do protocolo
estabelecido pelo circuito do braco robo.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 39
• O envio de comandos para o braco robo e realizado na linha 118 por intermedio
da funcao write que envia o comando a ser realizado, utilizando para isso o
descritor do arquivo aberto na linha 64. A funcao write funcao o numero de bytes
enviados, ou –1 caso tenha ocorrido um erro.

• Notar o uso do flag FNDELAY na funcao fcntl (linha 122) para configurar a
operacao de leitura nao-bloqueante do status da serial. Esse flag faz com que a
funcao read retorne 0, caso nao existam dados disponiveis para serem lidos na
porta serial.

• A seguir sao apresentados programas para acesso a porta paralela. Caso os


programas nao consigam escrever/ler o dado desejado na porta, verificar as
possiveis causas:

o Escrita no endereco errado (378H equivale a 888 em decimal).


o O cabo/conectores podem estar ligados de forma incorreta. Verificar!
o O dispositivo conectado a porta esta causando o problema. Desconectar o
dispositivo, e medir os bits da porta para ver se eles estao sendo alterados
corretamente pelo programa no computador pessoal.
o Os bits 0, 1 e 3 no registrador de controle das portas sao invertidos entre o
registrador e o conector. Ao se escrever no registrador de controle, esses
bits apareceram nos pinos do conector com valores invertidos em relacao
aos escritos.
o A porta suporta modo PS/2 e foi escrito 1 no bit 5 do registrador de
controle. Isso desabilita a porta para saida de dados. Escrever 0 no bit 5 do
registrador de controle para habilitar a saida.
o Um driver de baixo-nivel do Windows esta proibindo o acesso a porta.

• Caso o valor lido da porta nao e o esperado verificar, alem dos itens acima:

o Os bits 0, 1 e 3 no registrador de controle das portas, e o bit 7 do


registrador de status sao invertidos entre o conector e os respectivos
registradores. Ao se ler desses registradores, os bits mencionados possuirao
valores invertidos em relacao aos existentes nos pinos do conector.
o A porta nao aceita o modo PS/2 e nao e possivel desabilitar o modo de
saida (unidirecional). O valor lido sera sempre o ultimo valor escrito.
o A porta suporta o modo PS/2, mas o bit 5 do registrador de controle nao foi
setado para 1 de forma a desabilitar o modo de saida da porta. Escrever 1
nesse bit de forma a habilitar a leitura nos pinos de dados da porta.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 40
Porta Serial RS-232C
Acesso via API – commapi
linguagem Java – Win32 e Solaris

• A commapi e uma API que pode ser utilizada por desenvolvedores em programas
em Java para acesso as portas de entrada e saida (paralela e serial). Os arquivos
dessa API podem ser obtidos na pagina do curso (ver Exercicio 3 da aula pratica),
e tambem dicas de instalacao e utilizacao.
• Para instalar a commapi no Windows e preciso ter permissao de escrita no
diretorio onde o jdk esta instalado. Para realizar a instalacao executar os seguintes
passos (<jdk> e o caminho onde o jdk esta instalado):
o Copiar o arquivo win32com.dll para o diretorio <jdk>\jre\bin
o Copiar o arquivo comm.jar para o diretorio <jdk>\jre\lib\ext
o Copiar o arquivo javax.comm.properties para o diretorio <jdk>\jre\lib
• Uma dica extra e a execucao da aplicacao utilizando a virtual machine (java) que
se encontra no mesmo diretorio do arquivo win32com.dll (<jdk>\jre\bin). O
ambiente pode estar configurado para ser utilizado outro java, e nesse caso o
programa nao funcionara corretamente.
• A melhor forma de entender o funcionamento dessa API e por meio do estudo
das aplicacoes exemplo que acompanham os arquivos. Um bom ponto de partida
e a aplicacao “Serial Demo”. O arquivo README que acompanha essa aplicacao
contem dicas de compilacao e utilizacao.
• Na classe SerialConnection da aplicacao SerialDemo, observar:

o O metodo openConnection(), na linha 90, abre uma porta serial.


o O metodo closeConnection(), na linha 203, fecha uma porta serial
liberando a mesma para uso por outra aplicacao.
o O metodo setConnectionParameters(), na linha 167, utilizado para
configurar (programar) a porta serial com os parametros fornecidos pelo
usuario.
o O metodo serialEvent(), na linha 255, utilizado para avisar a aplicacao
sobre a chegada de dados na porta serial, e recepcao desses dados.
o O metodo keyTyped(), na linha 330, utilizado para envio de dados para a
porta serial. Cada caracter digitado na caixa de texto e enviado
automaticamente para a porta serial aberta.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 41
Porta Paralela
acesso direto ao hardware – inportb, outportb
linguagem C – MS-DOS/Windows 9x

• A porta paralela pode ser acessada de forma semelhante a porta serial, utilizando
acesso direto ao hardware por intermedio da funcoes outportb (int porta,
unsigned char valor); e inportb (int porta);, como mostrado no programa a
seguir:
/* par_io.c - Programa em C para gerencia da porta paralela utilizando
acesso direto ao hardware pelas instrucoes IN e OUT.

Eduardo Augusto Bezerra, Maio de 2003

compilador Turbo C++ versao 1.0 (Borland)


*/
#include <stdio.h>
#include <dos.h>
#include <conio.h>
#define DADOS 0x0378
#define STATUS 0x0379
#define CONTROLE 0x037A

int main(){
int opcao = 0;
unsigned char caracter = 0, aux;

while (opcao != 4){


clrscr();
printf("Entre com:\n");
printf("\t\t\t1 - Enviar caracter para a paralela\n");
printf("\t\t\t2 - Receber um caracter pela paralela\n");
printf("\t\t\t3 - Reservado\n");
printf("\t\t\t4 - Sair do programa\n");
opcao = getch() - '0';
caracter = '';
/* transmissao de um caracter */
if (opcao == 1)
while (caracter != 0x1B){ /* repete ate' pressionar ESC */
printf("\nEntre com o carcter a ser transmitido ... ");
caracter = getch();
printf("%c", caracter);
outportb(DADOS, caracter);
}
/* recepcao de um caracter */
if (opcao == 2){
printf("\n\nAguardando caracter na porta paralela ... ");
for (;;){
if (kbhit() && getch()) break;
aux = inportb(DADOS); /* recebe um caracter */
printf("\nRecebido o caracter --> %c", aux);
}
}
}
return 0;
}

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 42
Porta Paralela
Uso de interrupcoes – int 17H
linguagem C – MS-DOS/Windows 9x

• Outra forma de acesso a porta paralela no Windows e por intermedio interrupcao


17H da BIOS. Uma observacao importante e que essa interrupcao visa gerenciar
impressoras conectadas a porta paralela. Um outro dispositivo qualquer
conectado a porta paralela podera ser controlado com a int 17H, caso seja
projetado de acordo com as tres funcoes disponiveis por essa interrupcao da
BIOS: 00H para envio de caracteres do computador pessoal para o dispositivo;
01H para inicializar (boot) o dispositivo; e 02H para ler o status do dispositivo.
Esse dispositivo devera ser implementado de forma a enviar os sinais de ACK
para o computador pessoal, emulando assim o comportamento de uma
impressora.

• O programa a seguir utiliza a int 17H da BIOS para enviar o caracter ‘A’ para
uma impressora (ou dispositivo que se comporte como uma impressora)
conectada a porta paralela:
#include <dos.h>
#define INT_PARALELA 0x17
int main(){
union REGS r;
unsigned char caracter = 'A';

r.h.ah = 0x01; /* AH = funcao (01H = inicializa a porta) */


r.x.dx = 0x00; /* DX = nr. porta paralela (0, mas aceita tambem 1 e 2) */
int86(INT_PARALELA, &r, &r);
/* essa chamada retorna em AH (ou r.h.ah ) o status do dispositivo */
r.h.ah = 0x00; /* AH = funcao (00H = envia caracter para a porta) */
r.h.al = caracter; /* AL = caracter a ser enviado */
r.x.dx = 0x00; /* DX = nr. porta paralela (0, mas aceita tambem 1 e 2) */
int86(INT_PARALELA, &r, &r);
/* essa chamada retorna em AH (ou r.h.ah ) o status do dispositivo */
/* Status da impressora (registrador AH):
bit
0 Erro de time out
1 Nao utilizado
2 Nao utilizado
3 Erro de transferencia
4 A impressora esta on-line
5 Impressora sem papel
6 Mode de recepcao foi selecionado
7 Impressora ocupada
*/
return 0;
}

• Apos a execucao da funcao int86() no programa acima, o caracter ASCII ‘A’


ficara armazenado no registrador de dados da porta paralela, e consequentemente
disponivel nos pinos de saida da porta (conector), ate que um novo dado seja

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 43
escrito nessa porta. Lembrar que o ASCII ‘A’ equivale a 41H ou 01000001 em
binario.

Porta Paralela
acesso direto ao hardware – inb, outb
linguagem C++ – Linux
/*
* Parallel Port Comunication
* (c)Diogo Becker de Brum, 2002
*
* Last change: 05/06/2003
* Changed by: Eduardo Augusto Bezerra
*
* compiler: g++ (as root)
*
* chmod 4755 ./a.out to allow users to open the parallel port
* using setuid (see below)
*/
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <sys/io.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>

#define DELAY 10000


#define BASEPORT 0x378

using namespace std;

class Lpt {
public:
Lpt();
void init();
void send(char aByte);
char read();
void finish();
};

void Lpt::init(){
int a;
a = setuid(0);
printf("setuid = %d\n", a);
if (ioperm(BASEPORT, 2, 1)) {
perror("ioperm");
printf("Erro: Nao liberou a porta paralela!");
}
}

void Lpt::send(char aByte){


outb(aByte,BASEPORT);
usleep(DELAY);
}

char Lpt::read(){
char a;
a = inb(BASEPORT);
usleep(DELAY);
return a;
}

void Lpt::finish(){

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 44
if (ioperm(BASEPORT, 2, 0))
{
perror("ioperm");
}
}

int main(){
int a = 0;
Lpt lpt;
lpt.init();
lpt.send((char)0x00);
printf("Leu: %d\n", lpt.read());
cin >> a;
lpt.send((char)0x55);
printf("Leu: %d\n", lpt.read());
cin >> a;
lpt.send((char)0x0FF);
printf("Leu: %d\n", lpt.read());
cin >> a;
lpt.send((char)0x80);
printf("Leu: %d\n", lpt.read());
cin >> a;
lpt.send((char)0x08);
printf("Leu: %d\n", lpt.read());
cin >> a;
lpt.send((char)0x01);
printf("Leu: %d\n", lpt.read());
cin >> a;
lpt.send((char)0x00);
printf("Leu: %d\n", lpt.read());
cin >> a;
lpt.finish();
}

Porta Serial RS-232C


Acesso em Java via Java Native Interface (JNI)
linguagens Java, C++ – Win32 e Linux

Sockets
Acesso a dispositivo conectado a outro computador da rede
linguagem Java – Win32, Linux

Internet
Acesso usando browser com dispositivo conectado a
outro computador na Internet
linguagens HTML, Java, Servlet, C++ – J2EE, Win32 e Linux

• As tres formas de acesso acima sao demonstradas com o auxilio da aplicacao


WebRobot. Essa aplicacao utiliza esses tres conceitos, conforme mostrado no
diagrama a seguir.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 45
• Todos os fontes que compoem essa aplicacao estao disponiveis para download
em:
http://www.inf.pucrs.br/~eduardob/disciplinas/extensao/Robot/WebRobot/
• Os seguintes diretorios contem os arquivos dessa aplicacao:
Client/
Contem robot_client.html que e o cliente em HTML. Notar na linha 141 a chamada
ao programa servlet RobotServlet.class para passar o conteudo dos campos do
formulario: <form method="POST" action="/robot/servlet/RobotServlet">. Essa
chamada e realizada quando o usuario pressiona “Submit” no browser.
servlet/

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 46
Contem RoboServlet.java que e o programa em Java (servlet) a ser executado no
servidor J2EE. Esse programa utiliza a classe HttpServletRequest para se comunicar
com o cliente HTML. Por exemplo, para obter o conteudo do campo Acao do
formulario, ou seja, movimento a ser realizado pelo braco robo, o programa utiliza:
String userAcao = (String)request.getParameter("Acao");

O servlet tambem realiza a conexao via sockets a maquina onde o robo esta
conectado. Para isso e preciso informar o endereco IP da maquina remota e a porta a
ser utilizada (linhas 64 e 65):

String serverURL = "200.17.91.157";


int porta = 5001;

Apos isso basta criar a nova conexao socket (linha 73) e o stream de saida (linha 74):

try{
mySocket = new Socket(serverURL,porta);
out = new DataOutputStream(mySocket.getOutputStream());
in = new DataInputStream(mySocket.getInputStream());

O envio da string via sockets e realizado na linha 77:

out.writeUTF(userName + "#" + userAcao);

Caso a maquina remota esteja desligada ou caso o servidor socket nao esteja em
execucao naquela maquina, entao mensagens de erro sao fornecidas ao usuario
(cliente HTML):

}catch (UnknownHostException e) {
outClient.println("<center><h2> ERRO: Nao encontrou host: ... </h2></center>");
}catch (IOException e) {
outClient.println("<center><h2>ERRO: Sem conexao de I/O para: </h2></center>");
}

O arquivo HOW-TO-COMPILE-JAVAX.SERVLET.TXT contem dicas de como compilar o


programa em java. O arquivo RobotServlet.class gerado deve ser colocado no
servidor J2EE.
RobotSocketJNI/
Esse diretorio contem os programas em C++ utilizados para acesso a porta serial no
Linux (vide descricao de um dos modulos desse programa fornecida anteriormente):
Robot.h, Robot.cpp, RobotLinux.h, e RobotLinux.cpp. No programa em C++
RoboProxy.cpp, sao informadas as funcoes (metodos) a serem utilizados poelo

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 47
programa em Java (JNI), que no caso sao openSerial e sendCommand. Notar a
sintaxe JNI utilizada nesse programa para a definicao das funcoes. O arquivo
RobotProxy.h e automaticamente gerado pelo compilador javah a partir do
RobotProxy.class (gerado a partir do Robot Proxy.java).

O principal programa desse diretorio e o RobotLinuxSocketserver.java. Essa classe


implementa o servidor sockets, e possui tambem chamadas aos metodos nativos
(JNI) para envio de comandos para o robo via porta serial. Notar o uso de robot do
tipo RobotProxy para acesso as funcoes em C++.

No main desse programa e instanciado o objeto socket:

RobotLinuxSocketserver socketServer = new RobotLinuxSocketserver();

O programa entra entao em um laco infinito aguardando por mensagem na porta


5001 utilizada pelo socket para comunicacao com o socket no servidor J2EE. Ao
receber uma string do pela porta 5001, o programa extrai a acao a ser executada pelo
braco robo, e envia o comando via chamada JNI para o programa em C++:

char resp = socketServer.sendCommand(cmd);

O programa em C++ por sua vez envia os comandos para o braco robo, utilizando o
protocolo definido pelo programa em execucao no microcontrolador no modulo de
controle do braco robo: envio de dois bytes. O primeiro byte sempre devera ser
0xc1, seguido pelo byte contendo o comando a ser realizado.

Para compilar o programa, utilizar o usuario serial (do grupo uucp) e executar o
Makefile:

make clean
make

Para executrar o servidor socket na maquina onde se encontra o braco robo, sempre
como usuario serial, executar o Makefile:

make runServer

• No mesmo endereco estao tambem arquivos com dicas de como realizar o deploy
da aplicacao no servidor J2EE (deploytool_HOWTO.html), e tambem o codigo
fonte em perl (perl_cgi) para processamento do formulario, caso nao tenha acesso
a um servidor J2EE:
http://www.inf.pucrs.br/~eduardob/disciplinas/extensao/Robot/WebRobot/

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 48
• Uma alternativa ao J2EE seria a utilizacao do Jboss (http://www.jboss.org),
totalmente gratuito, que pode ser executado diretamente na maquina onde o braco
robo se encontra. Nesse caso nao seria necessaria a comunicacao via sockets.

4. Exemplos de aplicacoes

a. LEDs e chave na porta paralela

• A placa possui um conjunto de 8 LEDs diretamente conectados aos 8 bits de


dados da porta paralela (MSB no pino 9 do conector DB-25, e LSB no pino 2 do
DB-25).

• As chaves estao conectadas nos pinos de status (pinos 11, 10, 12 e 13 do DB-25),
sendo alimentadas pelo pino 9 do proprio conector DB-25. Assim, quando for
desejado realizar uma leitura nas chaves, e preciso antes colocar um nivel logico
alto (1) no pino 9 (D7) do conector DB-25.

• O endereco para escrita nos LEDs e o 378H e a leitura das chaves deve ser
realizada no endereco 379H.

• Componentes da placa:

o 1 Conector DB-25 (macho);

o 8 resistores de 470 ohms;

o 4 resistores de 4K7 ohms (4.700 ohms);

o 1 chave de posicao – reed switch;

• As figuras a seguir mostram o diagrama de blocos do circuito e o layout da placa.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 49
Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 50
d. RS232C via radio (wireless)

• Nesta placa temos a utilização de um módulo transmissor e um receptor.

• Componentes da placa:

o Conector DB9 (fêmea) utilizado para conectar na porta serial do computador,


no caso na porta COM0, nota-se que são utilizador apenas os pinos
necessários ficando os outros pinos soltos.

o MAX232 Circuito Integrado utilizado para compatibilizar os níveis de tensão


apresentados pela porta serial (-12V/+12V) com os níveis aceitos pelo
transmissor e pelo receptor (+5 volts), a alimentação do MAX232 deve ser de
+5V;

o Capacitores são utilizados para permitirem o funcionamento correto do


MAX232 conforme é apresentado em seu manual, existem dispositivos com a
mesma função e que possuem estas capacitores internamente, tornando o
circuito mais compacto;

o Power é um conector que permite ligar as tensões necessárias ao


funcionamento do receptor, transmissor e do MAX232;

o Transmissor é o dispositivo que recebe as informações da serial de forma


digital e envia para que os receptores possam utilizar os dados, o transmissor
utilizado aqui é o TWS-433 que trabalha com tensões de 1,5 até 12V;

o Receptor é o dispositivo que recebe as informações do transmissor e converte


em sinais digitais os quais são enviados para a porta serial, o receptor utilizado
é o RWS-433 que deve ter uma tensão de alimentação de +5V;

• Para realizar uma comunicação com envio e recepção de dados cada um dos
pontos deve ter um transmissor e um receptor;

• Para adquirir um par transmissor e receptor são necessários em torno de US$7.00


(Brasil/SP).

• As figuras a seguir mostram o diagrama de blocos do circuito e o layout da placa.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 51
J5
1
Antena Receptora

CONNECTOR_DB9 Receptor J2
1 gnd
6 U1 1
2 data 2
7 14 12 3 C5
3 13 T1OUT R1OUT 9 vcc5v 4
8 8 R1IN R2OUT 5 4.7n
4 7 R2IN 11 gnd 6
9 1u C1 T2OUT T1IN 10 ant 7
5 1 T2IN 8
3 C+
P1 4 C1-
C2 5 C2+ gnd
1u 2 C2- data 1
6 V+ D 12v 2 C6
C
C4 V- N C ant 3
G V 4 4.7n
C3 MAX232
1u 1u 5 6 Transmissor J1
1 1
VCC_CIRCLE
J4
1
0 Antena Transmissora
12v 5v gnd
J3
3 2 1
POWER

4. Exercicios praticos

I. Placa e cabo com conectores para conexao a porta paralela

Atividades

a. Aquisicao dos componentes


b. Soldagem dos componentes
c. Teste da placa/cabo

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 52
II. Controle do braco robo usando a linguagem C

Atividades

a. Leitura do material nas notas de aula para obter as dicas do


uso da linguagem C para acesso a portas seriais no Linux.
b. Desenvolvimento de um pequeno programa em C para
programacao da porta serial e envio de comandos para o braco
robo. Utilizar as dicas do programa em C++ das notas de aula.
c. Utilizar o conceito de arquivos (open, read/write, close)
para acesso a porta serial.
d. Para testar o programa em C no linux, e' preciso estar logado como
usuario do grupo UUCP. A senha de um usuario desse grupo sera'
fornecida durante a aula para os testes do programa.

III. Controle do braco robo usando a linguagem Java

Atividades

a. Leitura do material nas notas de aula para obter as dicas


de como utilizar a linguagem Java para acesso a porta serial.
b. Desenvolvimento de um pequeno programa em Java para
programacao da porta serial e envio de comandos para o braco
robo. Utilizar as dicas do programa SerialDemo nos exemplos
da commapi.
c. Utilizar a commapi para acesso a serial. Ler o FAQ da commapi, baixar os
arquivos, e ler as dicas de instalacao e utilizacao. Pesquisar no website
da Sun se existem versoes mais novas da commapi com suporte para Linux

IV. Acesso a placa com LEDs/chaves utilizando a porta paralela no Linux

Atividades

a. Escrever um programa em C ou C++ para o Linux utilizando o


conceito de acesso direto ao hardware (in, out) para acesso a porta
paralela. Ver dicas e programa exemplo nas notas de aula.
b. O programa devera' ler os sinais fornecidos pelas chaves e
escrever padroes nos LEDs.
c. Para testar o programa conectar a placa ao Laptop no qual
e' possivel compilar o programa como root.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 53
V. Comunicacao serial entre computador pessoal e placa com microcontrolador

Atividades

a. Configurar a porta serial do computador pessoal para 9600bps, 8 bits de


dados, 1 stop bit e sem paridade.
b. Envio de caracteres para a serial utilizando o Linux e C ou C++.

VI. Comunicacao serial entre computador pessoal e placa com reles (e


microcontrolador)

Atividades

a. Configurar a porta serial do computador pessoal para 9600bps, 8 bits de


dados, 1 stop bit e sem paridade.
b. Envio de caracteres para a serial utilizando o Linux e C ou C++.
c. O protocolo e' o seguinte: enviar na sequencia 'w', '4', '?', '0', 'X'

onde: '?' e' um valor em hexadecimal para acender os LEDs conectados aos
reles (um rele' para cada LED). O valor 1 acendera' um LED. Ex: F acende todos os
LEDs, e 0 apaga todos os LEDs.

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 54
Alguns links de interesse
• Outra opcao (alem da commapi) para comunicacao serial em Java:

http://www.frii.com/~jarvi/rxtx/download.html

• Dicas para o desenvolvimento de aplicacoes para USB, bem como classes


gratuitas para Java e C++:

http://jusb.sourceforge.net/

• Muita informacao interessante:

http://www.beyondlogic.org/

• Mais informacao:

http://www.cera2.com/WebID/software/index.htm

Resumo de dicas uteis encontradas nesse site:


Universal Serial Bus

• USB in a Nutshell - Making sense of the USB standard


Now includes an example - PDIUSBD11 connected to a PIC16F87x

• USB1.1 Integrated Circuits

• USB 2 Integrated Circuits Updated with USBDeveloper.com Kits

• USB Device Driver Development

• USB Protocol Analysers

• Win 2000/XP Driver for DeVaSys USBLPT-PD11 USB Boards

• On-The-Go Supplement - Point-to-Point Connectivity for USB.

• USB with the simplicity of RS-232

Parallel Port Interfacing

• Interfacing the Standard Parallel Port

• Interfacing Example - 16 Character x 2 Line LCD

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 55
• Interfacing the Enhanced Parallel Port (EPP)

• Interfacing the Extended Capabilities Parallel Port (ECP)

• Parallel Port Debug Tool

RS-232 Interfacing

• Interfacing the Serial Port - Parts 1 and 2

• Interfacing the Serial Ports - Parts 3 and 4

• Quick & Light RS-232 Terminal

• RS-232 Protocol Analyser

Referencias Bibliograficas Utilizadas

• “PC Intern – The Encyclopedia of System Programming”. Michael Tisher and


Bruno Jennrich. Ed. Abacus, 1996, 985 pp.

Partes dessas notas de aula foram traduzidas diretamente desse livro.

• “The Hardware Bible”. (Electronic Edition) Winn L. Rosch. SAMs


Publishing, 1997.

Partes dessas notas de aula foram traduzidas diretamente desse livro.

• Muito material da internet!

Acessando Dispositivos Externos com Computadores Pessoais, FACIN, PUC-RS, Porto Alegre, RS, Junho de 2003. 56

Você também pode gostar