Programando a Porta Paralela em Visual Basic

 

    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.

Página principal