Informações sobre o curso.
Lendo ângulos
Através dos chips CD4051B e ADC0804
Por: Antônio Rogério Messias
Página 1 de 1     Home  Índice  
LENDO ÂNGULOS ATRAVÉS DOS CHIPs CD4051B e ADC0804 CONECTADOS À PORTA PARALELA
Para uso particular ou educacional.
Copyright(c) 1999-2006 ROGERCOM.COM
Todos os direitos reservados.


       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.


     Clique aqui. Download do programa LptAngulo.exe.



Volta à página principal. 
 

Índice dos artigos.

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