Interfacciare con un dispositivo esterno utilizzando la porta parallela del PC

Stampa
( 1 Vote ) 
Valutazione attuale:  / 1
ScarsoOttimo 
Categoria: Informatica
Data pubblicazione
Scritto da Equelna Visite: 2514

Interfacciare con un dispositivo esterno utilizzando la porta parallela del PC

Interfacciare con un dispositivo esterno utilizzando la porta parallela del PC

potendo indirizzare fino ad 1MB di memoria e 64k di linee di IO

Utilizzare la porta parallela del PC (per quelli che la hanno) per sviluppare, debuggare e quanto altro possa essere necessario nello sviluppo di dispositivi esterni al PC sia statici che controllati da un microprocessore o microcontroller.
Ho pensato che senza dover smontare il PC ed inserire schede con circuitazione adatta è più semplice usare la porta stampante parallela (oggi molto poco utilizzata) per lo scopo prefissomi.

Schema elettrico.


   

Funzionamento.

Iniziamo con lo schema delle connesioni della porta e del significato dei suoi pin.



 

 

 

 

 

 

 

 

 

 

 
come sono disposti e quali sono i registri interessati
 



I pin dal 2 al 9 sono i bit dei dati che vengono inviati / ricevuti dal IOPort di base e sono i soli che vengono utilizzati per tutte le operazioni di input/output.


Nome Data register Status register
LPT1 378h 379h
LPT2 278h 279h
 

Iniziamo dalla 74LS164 [U13] (serial in parallel out) che è il componente che ci consente di inviare i dati verso l'esterno. Essa ha il pin Dsa (Data serial input A) collegato al pin 2 (D0) del connettore 25 poli, il clock (CP) della stessa è connesso al 3 (D1) del connettore gli altri 6 pin (D2-D7) sono utilizzati per comandare la logica di controllo . Le uscite della 74LS164 sono collegate agli ingressi delle 74LS374 [U8, U9, U10] e della 74LS173 [U12]  che compongono i registri di out per l'interfacciamento verso l'esterno.

Le due 74LS374 [U8, U9] più la 74LS173 [U12] sono i registri degli indirizzi, mentre la 74LS374 [U10] è il port di uscita dei dati.

La 74LS244[U11] è il buffer di separazione tra il Data-Bus e la 74LS165[U7] (parallel in serial out) che insieme a U14 e U1 e U2 compongono il sistema di lettura dei dati.

La logica di controllo è formata da U3, U4, U5, U6.

U4A in abbinamento a U3A e U4B decodifica il comando F4h che serve ad effettuare il reset di U13 e U14.

U1 (74LS30) decodifica il comando FCh che comandi il pin di Set di U14.

U6 (74LS139)  sezione B serve a dare i comandi per assegnare il dato inviato al giusto posto:

Uscita Comando Dato da inviare vs P.Par.
pin 9 CP 74LS173 [U12] 98h seguito da 84h
pin 10 CP 74LS374 [U8] 90h seguito da 84h
pin 11 CP 74LS374 [U9] 88h seguito da 84h
pin 12 CP 74LS374 [U10] 80h seguito da 84h

Il primo valore è il comando che effettivamente attiva la 74LS139 mentre il secondo la riporta nello stato non selezionato in quanto pone il pin 15(Eb) ad 1.

La 74LS139 sez. A serve a definire quale delle quattro operazioni deve essere eseguita

Uscita Operazione Dato da inviare vs. P.Par
pin 4 IOWR 24h seguito da 84h
pin 5 MEMWR 04h seguito da 84h
pin 6 IORD 44h deguito da 84h
pin 7 MEMRD 64h seguito da 84h

Anche in questo caso il primo dato è l'operazione ed il secondo riporta la 74LS139 nello stato di non selezionato U5A+U5B+U5C sono compongono un AND 4 ingressi che serve ad abilitare le uscite delle 74LS374 [U8, U9]  e della 74LS173 [U12].
Il pin di uscita U5A (3) comanda i gate di controllo della 74LS244 ed effettua il caricamento del dato nella 74LS165 [U7] quando l'operazione richiesta è MEMRD o IORD.
Il pin di uscita U5B (6) comanda il gate di controllo della 74LS374 [U11] quando l'operazione richiesta e MEMWR o IOWR.
Da notare che quando sono richieste operazioni  IORD o IOWR U12  viene resettato per cui le sue uscita saranno sempre a livello logico basso.
Sequenza logica di invio di un dato vs una locazione di memoria.

Invio F4h - reset sia il DFF che lo shift di input

Invio MSBite di ADDR-Bus

Invio 98h + 84h (memorizza il valore in U12)

Invio HBite di ADDR-Bus
Invio 90h + 84h (memorizza il valore in U

Invio LBite di ADDR-Bus

Invio 88h + 84h (memorizza il valore in U9)

Invio Dato

Invio 80h+84h (memorizza il valore in U10)

Invio 04h + 84h (comandi di MEMWR)

Di seguito due blocchi di codice in C++

Accesso alla memoria

#include "stdafx.h"
#include "MemoryIO.h"
#include "conio.h"
#include "math.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

MemoryIO::MemoryIO()
{

}

MemoryIO::~MemoryIO()
{

}

void MemoryIO::MemoryWrite(int Port, int AddrLow, int AddrMid, int AddrHigh, long newVal)
{
  DataMemory=newVal;
 unsigned int o_port, rs;
 o_port=Port;
 rs = _outp(o_port,0xF4); // Clear shifter input data
 ClockToggleOut(o_port, AddrLow);
 rs = _outp(o_port,0x8;
 rs = _outp(o_port,0x84);
 ClockToggleOut(o_port, AddrMid);
 rs = _outp(o_port,0x90);
 rs = _outp(o_port,0x84);
 ClockToggleOut(o_port, AddrHigh);
 rs = _outp(o_port,0x9;
 rs = _outp(o_port,0x84);
 ClockToggleOut(o_port, DataMemory);
 rs = _outp(o_port,0x80);
 rs = _outp(o_port,0x84);

}

int MemoryIO::MemoryRead(int Port, int AddrLow, int AddrMid, int AddrHigh)
{
 unsigned int o_port, rs;
 int DShifted;
 o_port=Port;
  rs = _outp(o_port, 0xFC); // Enable read data
 ClockToggleOut(o_port, AddrLow);
 rs = _outp(o_port,0x8;
 rs = _outp(o_port,0x84);
 ClockToggleOut(o_port, AddrMid);
 rs = _outp(o_port,0x90);
 rs = _outp(o_port,0x84);
 ClockToggleOut(o_port, AddrHigh);
 rs = _outp(o_port,0x9;
 rs = _outp(o_port,0x84);
 // Invia MEMRD
 rs = _outp(o_port,0x44);
 rs = _outp(o_port,0x84);
 DShifted=ClockToggleIn(o_port, 0x84);
 return DShifted;
}

int MemoryIO::ClockToggleIn(unsigned int o_port, int Dato_In)
{
 unsigned int i_value=0;
 int o_dato, i, rs, cmd;
 cmd=0x84;
 o_dato=0;
 for (i=0;i<8;i++)
 {
  rs=_outp(o_port,(cmd | 0x02));
  rs=_outp(o_port,(cmd & 0xFD));
  i_value = _inp(o_port);
  i_value = (i_value & 0x01);
  o_dato=o_dato | i_value;
  o_dato=o_dato << 1;
    
 }
 return o_dato;
}

void MemoryIO::ClockToggleOut(unsigned int o_port, int Dato_Out)
{

 int o_dato, i, s_dato, rs, cmd;
 cmd=0x84;
 o_dato=Dato_Out;
 for (i=0;i<8;i++)
 {
  o_dato=(int)pow(2,i);
  s_dato=Dato_Out & o_dato;
  s_dato=o_dato >> i;
  rs=_outp(o_port,(cmd | s_dato));
  rs=_outp(o_port,(cmd | s_dato | 0x02));
  rs=_outp(o_port,(cmd | s_dato & 0xFD));
  
 }
}

Accesso ad un device di IO

#include "stdafx.h"
#include "DeviceIO.h"
#include "conio.h"
#include "math.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

DeviceIO:eviceIO()
{

}

DeviceIO::~DeviceIO()
{

}

void DeviceIO:eviceWrite(int Port, int PortLow, int PortHigh, long newVal)
{
  DataDevice=newVal;
 unsigned int o_port, rs;
 o_port=Port;
 rs = _outp(o_port,0xF4); // Clear shifter input data
 ClockToggleOut(o_port, PortLow);
 rs = _outp(o_port,0x8;
 rs = _outp(o_port,0x84);
 ClockToggleOut(o_port, PortHigh);
 rs = _outp(o_port,0x90);
 rs = _outp(o_port,0x84);
 ClockToggleOut(o_port, DataDevice);
 rs = _outp(o_port,0x24);
 rs = _outp(o_port,0x84);

}

int DeviceIO:eviceRead(int Port, int PortLow, int PortHigh)
{

 unsigned int o_port, rs;
 o_port=Port;
 rs = _outp(o_port, 0xFC); // Enable read data
 ClockToggleOut(o_port, PortLow);
 rs = _outp(o_port,0x8;
 rs = _outp(o_port,0x84);
 ClockToggleOut(o_port, PortHigh);
 rs = _outp(o_port,0x90);
 rs = _outp(o_port,0x84);
 // Invia un IORD
 rs = _outp(o_port,0x64);
 rs = _outp(o_port,0x84);
 DataDevice =ClockToggleIn(o_port, 0x84);
 return DataDevice;
}

int DeviceIO::ClockToggleIn(unsigned int o_port, int Dato_In)
{
 unsigned int i_value=0;
 int o_dato, i, rs, cmd;
 cmd=0x84;
 o_dato=0;
 for (i=0;i<8;i++)
 {
  rs=_outp(o_port,(cmd | 0x02));
  rs=_outp(o_port,(cmd & 0xFD));
  i_value = _inp(i_port);
  i_value = (i_value & 0x01);
  o_dato=o_dato | i_value;
  o_dato=o_dato << 1;
    
 }
 return o_dato;
}

void DeviceIO::ClockToggleOut(unsigned int o_port, int Dato_Out)
{

 int o_dato, i, s_dato, rs, cmd;
 cmd=0x84;
 o_dato=Dato_Out;
 for (i=0;i<8;i++)
 {
  o_dato=(int)pow(2,i);
  s_dato=Dato_Out & o_dato;
  s_dato=o_dato >> i;
  rs=_outp(o_port,(cmd | s_dato));
  rs=_outp(o_port,(cmd | s_dato | 0x02));
  rs=_outp(o_port,(cmd | s_dato & 0xFD));
  
 }
}

Va fatto presente che nei due codici di esempio le istruzioni _outp(port,dato) e _inp(port) sono valide solo solo nel caso che il sistema operativo utilizzato sia precedente a Windows 2000 o DOS. Se si utilizza 2000,XP vanno ricercate in rete le librerie che consentono di accedere ai port del sistema come per esempio WinIO e di conseguenza sostituire le funzioni con quelle corrispondenti.

Avevo in mente di proporvi un programma che consentisse di gestire con una interfaccia accattivante per il dispositivo proposto, ma non ho avuto il tempo di implementarlo. Spero quanto prima di portervi offrire anche questo strumento.

Allego lo sbroglio del CS in ExpressPCB per coloro che non vogliono saldare su circuiti di prova.

infoportal.it/uploads/fckeditor/equelna/file/PCSerialIO-2.pcb

 
Saluti a tutti e buone saldature

Joomla 1.7 Templates designed by College Jacke