Esta é uma simples introdução à programação da porta paralela do PC em Visual Basic. 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 Visual Basic.
Antes de prosseguir, devemos citar algumas limitações do
Visual Basic. O VB não pode acessar diretamente o hardware do sistema. Todas as
requisições de hardware devem ser feitas atravás do Windows. Devido a esse fato, o mais
próximo que podemos chegar da porta paralela é o objeto Printer. Isto é útil quando se
quer printar algo, porém é inútil quando se quer controlar o hardware. A fim de
controlar a porta diretamente, devemos usar algo externo ao nosso programa. Felizmente
existe uma solução, usando uma DLL que poderá controlar a porta
diretamente. Você pode fazer o download dessa DLL no nosso site, na seção
Downloads. Use a WIN95IO.DLL a
partir do VB 5. Deverá ser instalada no diretório C:\windows\system. Por questões de segurança, esta DLL não funcionará no Windows NT.
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, 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ório, e atuará independente do resto, quase como se fossem independentes.
Os respectivos endereços são mostrados abaixo :
| Port | Address (Decimal) | Address (Hex) |
| Data Lines | 888 | 378h |
| Control Lines | 890 | 37Ah |
| Status Lines | 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.
Antes de você usar qualquer das funções contidas na DLL, devemos declará-las. Estas declarações deverão ser colocadas em qualquer módulo de seu programa, na seção General_Declarations.
Use a DLL (WIN95IO.DLL) :
Declare Sub vbOut Lib "WIN95IO.DLL" (ByVal nPort As Integer, ByVal nData As Integer) Declare Sub vbOutw Lib "WIN95IO.DLL" (ByVal nPort As Integer, ByVal nData As Integer) Declare Function vbInp Lib "WIN95IO.DLL" (ByVal nPort As Integer) As Integer Declare Function vbInpw Lib "WIN95IO.DLL" (ByVal nPort As Integer) As Integer
Uma vez declaradas as funções, você terá 2 novos
comandos disponíveis : vbInp e vbOut. A função vbOut
é usada para enviar um bit para a porta, como mostrado a seguir:
vbOut [port],[number]
A instrução vbInp será
vista mais tarde. Como se pode ver, os 2 parâmetros necessários 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
vbOut 888, 0
'seta a porta em 10000000
vbOut 888, 1
'seta a porta em 01000000
vbOut 888, 2
'seta a porta em 00100000
vbOut 888, 4
'seta a porta em 00010000
vbOut 888, 8
É claro que você pode mudar mais de 1 bit:
'seta a porta em 10110000
vbOut 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 vbInp.
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 vbInp. A sintaxe deste comando é a seguinte :
[variable]=vbInp([port])
Se você quiser saber o estado atual da porta 889, devemos usar :
PortNum%=vbInp(889)
PortNum% deveria
conter a representação decimal da combinação binária presente nas 5 linhas de estado.
Se você obtiver 31 (11111) não se surpreenda. Quando não há nada conectado na entrada
de um chip TTL, um nivel high é assumido.
Você pode não apenas usar as portas como entrada, mas também usar a instrução vbInp para ler o estado de saída da porta. Por exemplo :
PortNum%=vbInp(888)
O acima explicado setaria PortNum%
com o valor atual da linha de dados (porta 888). Podemos provar isso fazendo o seguinte:
vbOut 888, 56
PortNum%=vbInp(888)
MsgBox 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% = vbInp(PortAddress%)
PortNum% = PortState% + OutNum%
vbOut 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% = vbInp(PortAddress%)
PortNum% = PortState% + OutNum%
vbOut PortAddress%, PortNum%
IF OutNum% = 0 THEN vbOut 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 vbInp. 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% = vbInp(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%
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.
Por exemplo, para ler o bit 5 da porta 888, você deverá usar :
Bit5Variable% = BitStatus%(888, 5)
Se você estiver interessado, poderá ver o tópico Programando a Porta Paralela em QBasic.