Há muitas aplicações práticas importantes que utilizam a porta paralela e as funções de acesso ao disco rígido para entrar ou retirar dados como, por exemplo: programadores de memórias, osciloscópios virtuais, sensores matriciais com arrays; etc. Neste artigo, apresentamos as funções principais para transferir dados (nos dois sentidos) entre a porta paralela e o disco rígido.

 

Nota: O artigo é de 2002

 

A unidade fundamental de armazenamento de dados para o disco rígido é o arquivo (file). Os arquivos são conjuntos de dados, ou seja, uma sequência de dados similar à armazenada em uma memória RAM, PROM, EPROM, etc. Os dados em um arquivo podem ser acessados (endereçados) da mesma maneira que ao se endereçar uma memória. Normalmente, os endereços dos dados em um arquivo são acessados por um ponteiro que pode posicionar-se em qualquer parte do arquivo. Uma vez posicionado o ponteiro, podem ser empregadas funções de gravar/ler para acessar os dados.

Existe uma grande variedade de tipos de arquivos que são identificados pela extensão que segue seu nome, por exemplo: txt, pdf, asm, hex, etc. Cada um deles guarda dados que, na maioria dos casos, são textos, estruturas ou objetos. Os arquivos de texto guardam dados no formato de caracteres ASCII. As estruturas ou objetos são dados que contêm informações fundamentais encapsuladas, ou seja, de acesso restrito. Os objetos também contêm funções encapsuladas. Para desenvolvimento deste artigo usaremos o compilador Visual C++ da Microsoft (qualquer versão).

 

 

ESTRUTURAS E OBJETOS

 

A maioria dos arquivos está formada por Arrays de dados fundamentais (bytes, inteiros, etc...) caracteres, estruturas ou objetos. Os arrays de dados fundamentais ou caracteres são sequências de dados contendo o mesmo tipo de informação.

A seguinte linha de código declara um Array de inteiros que só pode armazenar valores inteiros:

int Temperatura [2O];

Uma estrutura é composta por vários tipos de dados fundamentais que o programador pode definir e, normalmente, recebem o nome de variável ou dado membro. Mostramos, a seguir, um exemplo de como se define uma estrutura.

struct COMPONENTES

{

char Nome[30];

int Resistores;

int Capacitores;

int Semicondutores;

}

 

O próximo é um exemplo de como podemos declarar variáveis do tipo COMPONENTES:

COMPONENTES Amplificador;

Agora, temos um exemplo de como se associa valores às variáveis, membros da estrutura Amplificador.

Amplificador. Nome = "Rádio- 5 watts";

Amplificador. Capacitores = 24;

Amplificador.Resistores = 35;

Amplificados.Semicondutores = 3;

 

Nas linhas dos códigos anteriores, a estrutura Amplificador acessa e atribui valores aos seus elementos membros de uma maneira válida para o compilador. Se, por exemplo, usarmos as seguintes linhas de código para acessar uma variável membro, o compilador avisará que existe um erro:

Capacitores = 24;

 

A linha de código seguinte faz o acesso correto e, por este motivo, se diz que as variáveis, membros de uma estrutura estão encapsuladas. Ou seja, o acesso só pode ser feito para uma variável que tenha sido declarada na estrutura COMPONENTE. Para nosso exemplo, a variável é Amplificador.

Amplificador.Capacitores = 24;

 

Um objeto é uma estrutura que contém variáveis e funções membros. O seguinte, é um exemplo de como se declara e define uma classe:

 

class CCircuito;

{

protected:

char m_Nome[30];

int m_Resistores;

int m_Capacitores;

int m_Semicondutores;

int m_Total;

void Contador(void);

}

 

Vejamos agora como podemos declarar variáveis da classe CCircuito.

CCircuito Filtro;

 

O exemplo dado a seguir mostra como se atribuir valores às variáveis membros da classe Filtro.

Filtro.m_Nome = "Rádio- 5 watts";

Filtro. m_Capacitores = 24;

Filtro.m_Resistores = 28;

Filtro.rn_Semicondutores = 38;

Filtro.Contador();

 

Agora, o exemplo mostra como podemos definir a função membro Contador:

void CCircuito::Contador(void)

{

Filtro.m_Total =Fonte.m_Capacitores + Filtro. m_Resi stores + Filtro.m_Capacitores;

 

Depois que a função anterior for executada, a variável Filtro.m_Total armazenará a soma dos valores contidos nas outras variáveis. Além disso, essa função só pode ser chamada por um objeto do tipo CCircuito. Para nosso exemplo, o objeto Filtro. Se a linha seguinte de código for usada para chamar a função Contador, o compilador indicará erro.

Contador ();

 

A forma correta é através do objeto, conforme o exemplo:

Filtro.Contador();

 

O compilador Visual C++ tem uma grande quantidade de classes dedicadas com suas funções respectivas listadas para uso. Todas essas classes foram armazenadas numa biblioteca chamada Biblioteca de Classes da Microsoft ou MFC. Nessa biblioteca, por conveniência, todos os nomes das classes começam com a letra "C", e todos os nomes das variáveis membros começam com a letra

 

 

ACESSO AO DISCO RÍGIDO

 

Na biblioteca MFC existe uma classe dedicada ao acesso de dados para o disco rígido, chamada CFile. As principals funções da classe CFile são:

CFi le()

Open()

Close()

Read()

Write()

Seek()

SetToBegin()

GetLenght()

SetLenght()

GetPositionO

Duplicate()

Para poder acessar as funções anteriores, é preciso criar um objeto da classe CFile. Uma vez criado o objeto, é necessário relacioná-lo com um arquivo no disco rígido e assim saber onde as funções vão ler ou gravar os dados. Também é necessário abrir o arquivo antes de ler ou gravar dados e, uma vez terminadas as tarefas, fechar os arquivos.

 

A função CFile()

 

Esta função cria um objeto que pode usar as funções da classe CFile. A linha de código seguinte cria um objeto chamado f.

CFile f;

O passo seguinte é associar um arquivo ao objeto f.

 

 

A função Open()

 

Esta função abre um arquivo e o associa ao objeto f. Ela recebe dois parâmetros. O primeiro é o nome do arquivo e o segundo especifica a ação a ser realizada quando se abre o arquivo. As linhas seguintes de código abrem um arquivo chamado Paralela.txt.

char* ptrAr = "Paralela.txt";

f.Open (ptrAr, CFile::modeCreate I CFile::modeReadWrite);

A função Open, quando escrita empregando as opções do segundo parâmetro (CFile::modeCreate 1 CFile::modeReadWrite), testa se o arquivo existe. Se o arquivo não existe, a função Open cria o arquivo no disco rígido e depois o abre. Se o arquivo já existe, simplesmente o abre. A opção CFile::modeReadWrite permite leituras e gravações no arquivo. Quando o arquivo é aberto, o ponteiro é colocado na posição zero.

 

 

A função SetToBegin()

 

Esta função coloca o ponteiro no começo do arquivo. A linha de código seguinte executa essa operação:

f. SetToBegin();

Neste momento, o ponteiro do arquivo está endereçando a posição Zero (0) do arquivo.

 

 

A função Write()

 

Esta função grava dados num arquivo a partir do ponto em que se encontra o ponteiro do arquivo. Ela aceita dois parâmetros. O primeiro é um ponteiro de um buffer (conjunto) na memória RAM que contém os dados a serem gravados no arquivo. O segundo parâmetro é um número de bytes a serem transferidos para o arquivo. As linhas seguintes de código criam um buffer em RAM de 200 bytes e gravam seu conteúdo no arquivo.

char Buffer[200];

f.Write (Buffer,200);

Normalmente, os buffers são dotados de carregadores com alguns valores antes de usar a função Write. Aqui, por simplicidade, foram omitidos os atributos do buffer.

 

 

A função Read()

 

Esta função lê dados no arquivo a partir da posição em que se encontra seu ponteiro. Ela aceita dois parâmetros.

O primeiro é um ponteiro de um buffer na memória RAM de onde são recebidos os dados lidos no arquivo.

O segundo parâmetro é o número de bytes a ser lido do arquivo. As linhas seguintes de código criam um buffer de 200 bytes e os carrega com os primeiros 200 bytes armazenados no arquivo, a partir do ponto em que se encontra o ponteiro do arquivo.

char Buffer[200];

f.Read (Buffer,200):

 

 

A função Seek()

 

Esta função reposiciona o ponteiro em qualquer dado do arquivo. A função aceita dois parâmetros. O primeiro é o número de bytes para mover o ponteiro. O segundo é o modo de movimento do ponteiro. Há três modos para movimentar o ponteiro:

O modo CFile::begin move o ponteiro um número de bytes adiante a partir do começo do arquivo.

O modo CFile::current move o ponteiro um número de bytes a partir da posição em que o ponteiro se encontra.

O modo CFile::end move o ponteiro um número de bytes a partir do final do arquivo. Para usar este modo é necessário empregar números negativos de modo a se chegar aos dados do arquivos.

As linhas seguintes de código posicionam o ponteiro no endereço 32 do arquivo a partir da posição (0) do arquivo.

int ddrss = 32;

f.Seek(ddrss, CFile::begin);

É importante notar que a função Seek somente posiciona o ponteiro, mas não faz gravação ou leitura de dados no arquivo.

 

 

A função GetPosition()

 

Esta função retorna a posição real do ponteiro do arquivo. O valor retornado é um valor inteiro de 32 bits. Valores inteiros de 32 bits podem ser declarados como do tipo DWORD (palavra dupla). A linha seguinte de código obtém a posição real do ponteiro e a armazena na variável dwPosi.

DWORD dwPosi;

dwPosi = f.GetPosition

 

 

A função SetLenght()

 

Esta função muda o tamanho do arquivo. A função aceita um número que pode ser maior ou menor que o tamanho atual do arquivo. A linha seguinte de código muda o tamanho do arquivo para 2000 bytes.

DWORD dwLen = 2000;

f.SetLenght ( dwLen);

 

 

A função Close()

 

Esta função fecha o arquivo e apaga o objeto. Depois que esta instrução for executada, o arquivo estará indisponível para leitura ou gravação. A linha seguinte de código fecha o arquivo associado ao objeto f e, para o caso deste exemplo, o arquivo é Paralela.txt.

f.Clos();

 

Com as funções vistas, podem ser manipulados dados no disco rígido e eles podem ser enviados para a porta paralela byte por byte.

 


| Clique na imagem para ampliar |

 

 

 

ACESSO A PORTA PARALELA

 

Para acessar diretamente a porta paralela são usadas duas funções:

_outp()

_inp()

Essas funções se encontram no arquivo conio.h e, portanto, é necessário incluí-la nos códigos-fonte que as usem.

 

 

A função _outp()

 

Esta função coloca um byte à porta especificada na própria função. Ela aceita dois parâmetros. O primeiro é o endereço da porta e pode ser um inteiro curto sem sinal compreendido entre O e 65 535. O segundo parâmetro é o dado a ser colocado na porta e pode ser um valor inteiro compreendido entre os valores O a 255. A linha seguinte de código transfere o dado para o endereço 0x378, ou seja, o registro da porta paralela LPT1.

#define lptld 0x378

_outp (Iptld,5);

 

 

A função _inp()

 

Esta função lê um valor a partir da porta. Ela aceita um parâmetro que é o endereço da porta onde se deseja ler o dado. O parâmetro pode ser um inteiro curto sem sinal, entre 0 e 65 535. As linhas seguintes de códigos leem o registro de estado da porta paralela LPT1.

#define lptts 0x379

unsigned char valor;

valor = _inp( lpt I s);

Depois de executada esta instrução, a variável valor terá o dado encontrado nos pinos de entrada da porta LPT1. (Recordemos que o registro de estado tem o bit 7 invertido).

Com as funções vistas é possível ler a porta paralela e armazenar os dados em um buffer.

Depois, esse buffer pode ser armazenado no arquivo desejado no disco rígido.

Da mesma forma, podem ser lidos dados de um arquivo ou gravar para a porta paralela.

Assim funciona a transferência de dados entre a porta e o disco rígido.

Normalmente, dependendo da interface conectada na porta paralela, o programador deve montar um protocolo para assegurar a transferência correta de dados. Isso ocorre porque a maioria dos periféricos trabalha com pequena velocidade e, por isso, é necessário que o computador reconheça quando pode ler ou colocar um dado na porta.

Existem funções mais avançadas para a leitura e gravação de dados, tanto no disco rígido como nas portas, mas elas exigem o manuseio de interrupções ou funções de classes que podem controlar a entrada e saída de dados.

 

 

PARA SABER MAIS...

 

No site da microsoft www.microsoft.com  é possível encontrar diversas páginas relacionadas ao Visual C++. Outra alternativa é acessar o site da Borland ( www.borland.com ), onde além da versão trial do Borland C++ é possível encontrar diversas dicas.