Esta é uma simples introdução à programação da porta paralela do PC em QBasic, Quick Basic ou linguagem similar. Note que muitos dos conceitos mostrados nesta página também podem ser aplicados ao GWBASIC. Este documento não apresenta detalhes sobre o uso de portas bidirecionais, DMA e outros tópicos relacionados ao assunto. Este documento assume que você já esteja familiarizado com as funções básicas do QBasic.
A Porta Paralela é composta por 3 diferentes seções :
- Data Lines ou Linhas de Dados
- Control Lines ou Linhas de Controle
- Status Lines ou Linhas de Estado
Existem 8 linhas de dados, que são sempre saídas, geralmente utilizadas para enviar dados através da Porta. Em aplicações simples, você se concentrará principalmente nestas linhas. As linhas de controle são outras 4 saídas, cuja função é controlar a impressora, que é o dispositivo normalmente ligado na porta paralela. As linhas de status são linhas de entrada. Há 5 delas no seu PC, cuja função é receber informações da impressora, tais como erro, sem papel e porta ocupada.
Cada seção é acessada pelo seu endereço próprio, e atuará independente do resto, quase como se fossem independentes.
Os respectivos endereços são mostrados abaixo :
Porta |
Endereço (Decimal) | Endereço (Hex) |
Linha de Dados |
888 | 378h |
| Linhas de Controle | 890 | 37Ah |
| Linhas de Status | 889 | 379h |
Você precisará saber do endereço da porta que pretende utilizar, além de 2 outras coisas : o comando para acessar a porta, e o número que você deseja escrever nela. O comando será explicado rapidamente. As portas trabalham com números, que podem ser expressos em hexadecimal, binário ou decimal; neste documento lidaremos apenas com números decimais, para facilitar o aprendizado. De qualquer maneira, você opera a porta enviando um número que representa um padrão binário de uma saída física da porta. Por exemplo, para setar as 8 linhas em 11111111, você deverá escrever 255; para setá-las em 00000000 você deverá escrever 0. Note que estes são todos os números binários de 8 bits e a porta também tem 8 saídas. É coincidencia ? Não.
Agora que já sabemos como dizer à porta
qual a combinação binária que queremos, devemos então aplicar a linguagem QBasic. O
BASIC usa 2 comandos para conversar com a porta : OUT
e INP. A sintaxe da
instrução OUT é a seguinte :
OUT [port],[number]
A instrução INP será vista
mais tarde. Como se pode ver, os 2 parametros necessarios são o endereço da porta e o
dado que queremos escrever na mesma. O endereço pode ser hexadecimal ou decimal, assim
como o dado. Como existem somente 8 linhas de dados, o valor máximo enviado à porta
deverá ser 255 ( 11111111 em binário). Acompanhe os exemplos abaixo :
'seta a porta em 00000000
OUT 888, 0
'seta a porta em 10000000
OUT 888, 1
'seta a porta em 01000000
OUT 888, 2
'seta a porta em 00100000
OUT 888, 4
'seta a porta em 00010000
OUT 888, 8
É claro que você pode alterar mais de um bit:
'seta a porta em 10110000
OUT 888, 11
Note que quando você envia uma combinação binária para a porta, tudo que estava escrito anteriormente é apagado. Isto é conveniente e ao mesmo tempo atrapalha. Por exemplo, se quisermos que o bit 2 seja sempre 1, mas que o bit 5 fique se alternando entre 1 e 0 ou vice versa; discutiremos como resolver esse problema após explicar a instrução INP.
As linhas de controle são tão fáceis de controlar quanto as linhas de dados. Primeiro, o endereço da porta é 890 e segundo, existem somente 4 bits, o que significa que a máxima representação decimal será 15 (1111 em binário).
Se você quiser entrar com informação externa no computador, estará usando 5 linhas. A leitura de uma informação binária da porta será feita pela instrução INP. A sintaxe deste comando é a seguinte :
[variable]=INP([port])
Então para saber o status atual das linhas de estado (porta 889) utilizariamos :
PortNum%=INP(889)
PortNum% deverá então conter a representação decimal da
conbinação binária presente nas 5 linhas de status. Se você tentar isso sem nada
conectado à porta e obtiver o valor 31 (11111), não se surpreenda. Quando nada está
conectado à porta de um chip TTL, um nivel HIGH será geralmente assumido.
Você pode não apenas usar as portas como entrada, mas também usar a instrução INP para ler o estado de saída da porta. Por exemplo :
PortNum%=INP(888)
O acima explicado setaria PortNum%
com o valor atual da linha de dados (porta 888). Podemos provar isso fazendo o seguinte:
OUT 888, 56
PortNum%=INP(888)
PRINT PortNum%
Se tudo estiver correto, o numero 56 aparecerá na tela.
Agora já sabemos como a função INP
pode ser usada para manter o estado de um bit enquanto se muda o estado de outro. Para
isso definiremos a subrotina que utiliza as 2 funções :
SUB OutPort(PortAddress%, OutNum%)
PortState% = INP(PortAddress%)
PortNum% = PortState% + OutNum%
OUT PortAddress%, PortNum%
END SUB
Note como a sub soma o estado atual da porta ao numero que enviamos. Isto faz com que todos os bits anteriores fiquem no estado em que estavam, mas alternando o estado do bit ou bits novos que enviamos pela sub. Isto também requer uma mudança na maneira como a função é usada. Para setar o bit 1 em 1, teríamos.
OutPort 888, 1
Este exemplo supõe que o estado atual da porta é 0 (00000000). Se o bit 1 já está em high, você obteria resultados não esperados, portanto ter controle sobre a porta é muito importante. Para retornar o bit 1 a 0, teríamos:
OutPort 888, -1
Isto, porém introduziu um problema. Como
então limpar o conteúdo da porta, como se tivessemos enviado a instrução OUT
888, 0 ? Enviar 0 para a sub não tem nenhum efeito (somar ou subtrair 0 sempre
retorna o numero original), então precisamos adicionar uma instrução para
especificamente reagir com o 0. Isto é feito utilizando uma simples decisão IF...THEN
:
SUB OutPort(PortAddress%, OutNum%)
PortState% = INP(PortAddress%)
PortNum% = PortState% + OutNum%
OUT PortAddress%, PortNum%
IF OutNum% = 0 THEN OUT PortAddress%, 0
END SUB
A sub executa o seu papel normal, mas também seta a porta em 0 se um 0 foi enviado. Este é um método muito simples de zerar a porta se você acabou fazendo combinações binárias complexas tentando setar um bit high duas vezes. Você poderá querer ter controle sobre o conteúdo esperado da porta, com o resultado real usando a instrução INP. Se os 2 não coincidirem, limpe a porta e resete todos os bits usando outra variável.
Agora que sabemos algumas instruções uteis relativas às saídas, devemos analisar uma função muito importante. Quando utilizamos software nas portas de saída, precisamos saber o estado de um único bit de vez em quando. Há várias maneiras de fazer isto, mas acho que a função abaixo é a mais útil :
FUNCTION BitStatus(PortAddress%, BitYouWant%) AS INTEGER
IF PortAddress% = 888 THEN
NumOfBits% = 8
ELSE IF PortAddress% = 889 THEN
NumOfBits% = 5
ELSE
NumOfBits% = 4
REDIM PortBits(NumOfBits%) AS INTEGER
PortNum% = INP(PortAddress%)
FOR i = 1 To NumOfBits%
PortBits%(i) = PortNum% MOD 2
PortNum% = FIX(PortNum% / 2)
NEXT I
BitStatus% = PortBits%(BitYouWant%)
END FUNCTION
Primeiro a função decide com quantos bits
deve trabalhar, observando o endereço da porta. Note que em todos os outros exemplos era
realmente irrelevante se você usava endereços em decimal ou hexadecimal. Nesta função,
você precisará converter numeros se estiver trabalhando em hexa. Após decidir quantos
bits existem na porta, a função faz uma matriz com o mesmo numero de elementos. Entra
então num loop, executando uma divisão inteira com o numero retornado pela leitura da
porta. Executa uma divisão para cada bit da porta. Este é provavelmente o método mais
fácil para converter em binário, uma vez que o BASIC não tem instrução que transforme
decimal em binário. Repetindo, se você estiver trabalhando em hexa, terá que ajustar a
função aqui. A função, então atribui a si mesma o valor do elemento da matriz que
você especificou com a variavel BitYouWant%.
Por exemplo, para ler o bit 5 da porta 888, deveriamos usar :
Bit5Variable% = BitStatus%(888, 5)
O acima exposto não se limita à porta paralela. Você pode usá-lo com qualquer tipo de interface que utilize uma porta I/O standard. É claro que este código não seria ideal para controlar uma porta serial, pois muitas instruções simples seriam necessárias.
Se você estiver interessado, poderá ver o tópico Programando a Porta Paralela em Visual Basic.