O objetivo desse artigo
é desenvolver um projeto utilizando poucos componentes, com a
finalidade de gerenciar a interface de hardware e capturar os dados
digitais através da Porta Paralela, mostrando-os em forma de
gráficos na tela do computador através de um programa.
Para lê ângulos
iremos utilizar Potenciômetros de 10K ohm conectados às
8 entradas do Multiplexador analógico CD4051B
O CI CD4051B poder
ser usando tanto como um Multiplexador, com também um Demultiplexador
analógico. No projeto desse artigo iremos utilizá-lo como
um Multiplexador.
Num Multiplexador
digital de 8 bits, temos 8 entradas digitais podendo estas assumirem
valores binários (0 ou 1) e somente uma saída digital
variando de 0 a 1. Agora se utilizarmos o CD4051B como um Multiplexador,
temos disponíveis 8 entradas analógicas, cada uma dessas
entradas podendo assumir tensões entre 0 a 20v, e uma das saídas
assumindo respectivamente tensões entre 0 a 20v.
Algo em comum entre
os Multiplexador/Demultiplexador analógicos e digitais são
os seus seletores, todos são digitais, isso é muito importante
quando estamos trabalhando com circuitos mistos (analógico e
digital).
Com a utilização
do CI CD4051B ligado a um Conversor Analógico Digital de 8 bits
(ADC0804) podemos ter até 8 saídas digitais de 8 bits
cada. Então, poderemos criar uma interface que converta 8 grandezas
do mundo real como: temperatura, luminosidade, ângulos etc. em
8 saídas digitais de 8 bits cada, multiplexadas.
Veja abaixo uma animação
demonstrando o funcionamento básico de um CI CD4051B como Multiplexador:
Animação 1 - Funcionamento genérico
do CD4051B como Multiplexador
Na
animação acima, os três bits do SELETOR são
utilizados para escolher qual das entradas ficará ativa. Cada
entrada poderá aceitar entre 0 a 20v e a tensão que estiver
na entrada selecionada, será idêntica na saída.
Se na entrada 0 (zero) for aplicada uma tensão de 2,5v, a saída
apresentará também uma tensão de 2,5v. Ao selecionarmos
uma nova entrada através do SELETOR, e aplicarmos uma tensão
a esta, automaticamente esta tensão será idêntica
na saída.
No nosso projeto
para lê ângulos, cada entrada poderá variar entre
0 a 5v através dos Potenciômetros.
| Figura
1 - Foto de um Potenciômetro |
|
|
Figura
2 - Símbolo de um Potenciômetro
|
Um
potenciômetro é um resistor variável onde sua resistência
pode ser modificada através de movimentos mecânicos para
a direita ou esquerda.
Ligando o terminal 2 de
um potenciômetro ao pino 6 do ADC0804 podemos controlar a tensão
de entrada que será convertida em dados binários. Como
já foi mencionado em artigos anteriores, o ADC0804 converte tensões
de 0 a 5v com resolução de 0,0195V por passo. Portanto,
o ADC0804 converte uma tensão de 0v (zero volt) em um valor binário
de (00000000) em sua saída, e uma tensão de 5v em um valor
binário de (11111111) ou 255 em decimal. Ao girar o potenciômetro,
podemos variar a tensão elétrica que irá circular
no pino de entrada do ADC0804.
Figura
3 - Circuito multiplexador de 8 entradas analógicas

O
circuito acima é composto de duas partes importantes: uma é
a do multiplexador CD4051B que tem o objetivo de disponibilizar 8 entradas
analógicas, e a outra parte é a do Conversor Analógico
Digital (ADC0804), que tem a finalidade de converter em pequenos intervalos
de tempos as entradas analógicas em dados digitais.
Quem controla a seleção das entradas é o software
enviando uma seqüência binária de 0 a 7, respectivamente
000, 001, 010, 011, 100, 101, 110 e 111 através dos pinos 1,
14 e 16 do Registro de Controle da Porta Paralela. Esses pinos estão
ligados respectivamente aos pinos 11, 10 e 9 do SELETOR do CD4051B.
Nesse circuito o
Conversor Analógico Digital ADC0804 foi configurado para trabalhar
continuamente, ou seja, ao terminar de converter uma amostra analógica,
disponibiliza os dados digitais nas suas saídas (pinos 11 ao
18) e já começa a converter uma nova amostra. Para o ADC0804
trabalhar continuamente, foi ligado o pino 3 (WR) ao pino 5 (INTR) do
mesmo.
O esquema do circuito
acima mostra somente um Potenciômetro ligado ao Canal 0 (entrada
analógica 0) do CD4051B, mas para que possamos trabalhar coma
as demais entradas teremos que adicionar mais Potenciômetros para
completar as 8 entradas. Para isso, sigam o exemplo de instalação
do Pot. 1, no circuito.
Cada Potenciômetro
está alimentado com 5v, portanto, ao girá-lo para a esquerda
ou direita, ele variará a tensão no pino 2 entre 0 a 5v,
disponibilizando esta tensão a um dos canais do CD4051B. Esta
tensão de entrada no canal que está selecionado é
a mesma no pino 3 (saída do CD4051B), que está alimentando
a entrada do ADC0804. Assim, a cada canal selecionado, o ADC0804 converte
a tensão elétrica em dados digitais disponibilizando estes
à Porta Paralela.
Figura 4 - Tela do programa leitura de ângulos.

Os
gráficos acima foram criados através do componente
Pie
do C++Builder. O Delphi também tem esse componente.

Fonte 1 - Programa Principal para lê ângulos
através do circuito da Figura 3
|
//Curso Online C/C++ Porta Paralela.
//www.rogercom.com
//rogercom@rogercom.com
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include
"Unit1.h"
#include "porta.h"
#define BASE 0x378
#define DADOS BASE
#define CONTROLE BASE+2
#define ATIVA_EPP 32 //0010-0000 Ativa
o Modo EPP.
#define DESATIVA_EPP 0 //0000-0000
Desativa o modo EPP.
#define C0 0x01 //bits de registro
de Controle.
#define C1 0x02
#define C2 0x04
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "piereg"
#pragma resource "*.dfm"
TMultLinha
*MultLinha; //Cria
um objeto de Processos.
TForm1 *Form1;
//Cria um objeto com características
do formulário.
TPorta
*Lpt1; //Cria
um objeto para acesso a Porta Paralela.
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//Inicializa o construtor da classe
TMultlinha.
__fastcall TMultLinha::TMultLinha(bool
CreateSuspended) : TThread(CreateSuspended)
{
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
void __fastcall TMultLinha::Execute()
//Função/método
virtual da classe Thread.
{
unsigned char SelectCanalMux=0;
//Controla a exibição
dos gráficos de ângulos.
unsigned char ByteValor;
//Para armazenar temporariamente o
byte recebido do ADC0804.
unsigned char ByteAcerta;
//Para acertar os bits de controle
e controlar o seletor do CD4051B.
while(true) //Loop
infinito, é o coração do programa.
{
ByteAcerta =
SelectCanalMux; //Essa atribuição
é necessária para que a variável SelectCanalMux
não seja
//alterada
na correção dos bits através do operador
'^'
ByteAcerta =
(unsigned char)(ByteAcerta^C0);
//Corrige o bit 0 do Reg. de Controle.
ByteAcerta =
(unsigned char)(ByteAcerta^C1);
//Corrige o bit 1 do Reg. de Controle.
//Envia
Byte para o seletor do CI CD4051B mantendo o bit 5 (EPP) ativo.
Lpt1->Envia(CONTROLE,
(unsigned char)ATIVA_EPP |
ByteAcerta);
ByteValor =
Lpt1->Recebe(DADOS);
//Lê um byte do ADC0804.
switch(
SelectCanalMux ) //Escolhe o gráfico
de ângulo a cada passagem do loop.
{
case
0: Form1->LabelAngPot0->Caption = IntToStr(ByteValor)+"º";
Form1->Pie1->Angles->EndAngle
= ByteValor;
Form1->Pie1->Angles->StartAngle
= ByteValor+1;
break;
case
1: Form1->LabelAngPot1->Caption = IntToStr(ByteValor)+"º";
Form1->Pie2->Angles->EndAngle
= ByteValor;
Form1->Pie2->Angles->StartAngle
= ByteValor+1;
break;
case
2: Form1->LabelAngPot2->Caption = IntToStr(ByteValor)+"º";
Form1->Pie3->Angles->EndAngle
= ByteValor;
Form1->Pie3->Angles->StartAngle
= ByteValor+1;
break;
case
3: Form1->LabelAngPot3->Caption = IntToStr(ByteValor)+"º";
Form1->Pie4->Angles->EndAngle
= ByteValor;
Form1->Pie4->Angles->StartAngle
= ByteValor+1;
break;
case
4: Form1->LabelAngPot4->Caption = IntToStr(ByteValor)+"º";
Form1->Pie5->Angles->EndAngle
= ByteValor;
Form1->Pie5->Angles->StartAngle
= ByteValor+1;
break;
case
5: Form1->LabelAngPot5->Caption = IntToStr(ByteValor)+"º";
Form1->Pie6->Angles->EndAngle
= ByteValor;
Form1->Pie6->Angles->StartAngle
= ByteValor+1;
break;
case
6: Form1->LabelAngPot6->Caption = IntToStr(ByteValor)+"º";
Form1->Pie7->Angles->EndAngle
= ByteValor;
Form1->Pie7->Angles->StartAngle
= ByteValor+1;
break;
case
7: Form1->LabelAngPot7->Caption = IntToStr(ByteValor)+"º";
Form1->Pie8->Angles->EndAngle
= ByteValor;
Form1->Pie8->Angles->StartAngle
= ByteValor+1;
break;
default:
break; //Nenhuma
opção das anteriores.
}
SelectCanalMux++;
//Próximo canal a ser selecionado.
if(
SelectCanalMux > 7
) //Limite de um byte (8 bits).
{
SelectCanalMux
= 0;
//Inicializa variável.
}
Sleep(1);
//Intervalo de leitura entre cada
canal.
}
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
//É executado somente uma fez
quando o Formúlário é criado.
void __fastcall TForm1::FormCreate(TObject
*Sender)
{
MultLinha = new
TMultLinha(true); //Aloca
memória para o objeto.
MultLinha->Priority
= tpTimeCritical;
//Define a prioridade.
MultLinha->Resume();
//Logo que o programa é executado
a função virtual Execute() começará
a trabalhar.
Lpt1->Envia(CONTROLE,
ATIVA_EPP); //Ativa o bit 5 (00100000)
)do Rgistro de Controle.
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
void __fastcall TForm1::FormCloseQuery(TObject
*Sender, bool &CanClose)
{
MultLinha->Suspend();
//Suspende a execução
do processo;
delete
MultLinha; //Elimina objeto
da memória.
Lpt1->Envia(CONTROLE,
DESATIVA_EPP); //Desativa o bit 5
(00000000) )do Rgistro de Controle.
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
void __fastcall TForm1::BitBtn1Click(TObject
*Sender)
{
Close(); //É
capturado pela função FormCloseQuery() que fecha
o programa.
}
|
No
programa acima a variável SelectCanalMux
é
usada para controlar a leitura dos canais 0 a 7. Já a variável
ByteAcerta é
usada para controlar o SELETOR do CD4051B. As duas instruções
abaixo são utilizadas para corrigir os bits C0
e C1 do Registro de Controle.
ByteAcerta
= (unsigned char)(ByteAcerta^C0);
//Corrige o bit 0 do Reg. de Controle.
ByteAcerta = (unsigned
char)(ByteAcerta^C1); //Corrige
o bit 1 do Reg. de Controle.
Como já
sabemos, esses bits do Registro de Controle usam lógica invertida.
Se isso não fosse feito a seleção das entradas
do CD4051B seriam erradas.
A
instrução ByteValor = Lpt1->Recebe(DADOS)
é responsável em lê os dados digitais através
do ADC0804 referente a cada canal selecionado. A cada passagem do
loop um canal é lido.
A instrução
Sleep(1) foi utilizada para
definir um intervalo de tempo entre a leitura de cada canal.

Fonte 2 - Código fonte
do arquivo cabeçalho
Unit1.h com a declaração dos objetos e
metódos.
| //Curso
Online C/C++ Porta Paralela.
//www.rogercom.com
//rogercom@rogercom.com
//------------------------------------------------------------------------------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//------------------------------------------------------------------------------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
#include <Buttons.hpp>
#include "piereg.h"
//------------------------------------------------------------------------------------------------------------------------------------------------
//Esse código abaixo em vermelho
deve ser acrescentado pelo programador:
class TMultLinha : public TThread
{
private:
protected:
void __fastcall Execute();
public:
__fastcall TMultLinha(bool CreateSuspended);
};
//------------------------------------------------------------------------------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TLabel *LabelCanal0;
TPanel *Panel1;
TPie *Pie1;
TLabel *Label2;
TLabel *Label3;
TLabel *Label5;
TLabel *Label6;
TLabel *LabelCanal1;
TPanel *Panel2;
TPie *Pie2;
TLabel *Label7;
TLabel *Label8;
TLabel *Label9;
TLabel *Label10;
TLabel *LabelCanal2;
TPanel *Panel3;
TPie *Pie3;
TLabel *Label11;
TLabel *Label12;
TLabel *Label13;
TLabel *Label14;
TShape *Shape1;
TLabel *LabelCanal3;
TPanel *Panel4;
TPie *Pie4;
TLabel *Label15;
TLabel *Label16;
TLabel *Label17;
TLabel *Label18;
TLabel *LabelCanal4;
TLabel *LabelCanal5;
TLabel *LabelCanal6;
TPanel *Panel5;
TPie *Pie5;
TLabel *Label21;
TLabel *Label22;
TLabel *Label23;
TLabel *Label24;
TPanel *Panel6;
TPie *Pie6;
TLabel *Label25;
TLabel *Label26;
TLabel *Label27;
TLabel *Label28;
TShape *Shape2;
TPanel *Panel7;
TPie *Pie7;
TLabel *Label29;
TLabel *Label30;
TLabel *Label31;
TLabel *Label32;
TLabel *LabelCanal7;
TPanel *Panel8;
TPie *Pie8;
TLabel *Label34;
TLabel *Label35;
TLabel *Label36;
TLabel *Label37;
TShape *Shape3;
TShape *Shape4;
TShape *Shape5;
TShape *Shape6;
TShape *Shape7;
TShape *Shape8;
TLabel *LabelAngPot0;
TLabel *LabelAngPot1;
TLabel *LabelAngPot2;
TLabel *LabelAngPot3;
TLabel *LabelAngPot4;
TLabel *LabelAngPot5;
TLabel *LabelAngPot6;
TLabel *LabelAngPot7;
TBitBtn *BitBtn1;
void __fastcall FormCreate(TObject *Sender);
void __fastcall FormCloseQuery(TObject *Sender, bool &CanClose);
void __fastcall BitBtn1Click(TObject *Sender);
private: // User declarations
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//------------------------------------------------------------------------------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//------------------------------------------------------------------------------------------------------------------------------------------------
#endif |

Fonte 3 - Código fonte
do arquivo cabeçalho porta.h para controle da Porta Paralela
| #ifndef
portaH
#define portaH
class TPorta
{
public:
void __fastcall Envia(short
int PortaEnd, unsigned char Dado);
unsigned char __fastcall Recebe(short
int PortaEnd);
};
#endif |
O
código fonte acima é a declaração da classe
para controle da Porta Paralela.

Fonte 4 - Código fonte
do arquivo porta.cpp
com as funções membro para controle da
Porta Paralela.
| #include
<vcl.h>
#pragma hdrstop
#include "porta.h"
//------------------------------------------------------------------------------------------------------------------------------------------------
void __fastcall TPorta::Envia(short
int PortaEnd, unsigned char Dado)
{
_DX = PortaEnd;
_AL = Dado;
__emit__ (0xEE);
}
//------------------------------------------------------------------------------------------------------------------------------------------------
unsigned char __fastcall TPorta::Recebe(short
int PortaEnd)
{
_DX = PortaEnd;
__emit__ (0xEC);
return (_AL);
} |
O
código fonte acima implementa as funções membro
da classe para controle da Porta Paralela.
Download
do programa LptAngulo.exe.


http://www.rogercom.com
©
Copyright, 1999-2006 ROGERCOM - Antonio Rogério Messias
- rogercom@rogercom.com
Todos os Direitos Reservados - All Rights Reserved.
|