LPT-Schnittstelle auslesen
-
Hallo,
ich muss für ein Projekt die LPT ansteuern. Das habe ich auch Ausgangsseitig soweit hinbekommen, aber nun hat uns ein Lehrer aus reiner Schikane die Auflage gesetzt, dass auch Signale an den PC gesendet werden sollen.Ich habe mal ein kleines GUI-Programm geschrieben mit dem man schreibend und lesend auf die LPT-Schnittstelle zugreifen kann. Es hat eine ListBox zur Ausgabe und einen Button zum schreiben (mit Edit zum Wert angeben) und einen Button zum lesen. Die Ansteuerung macht es mit der inpout32.dll.
Hier mal der Code von den Buttons:
void __fastcall TForm1::btSchreibenClick(TObject *Sender) { short signal = StrToInt(edSchreiben->Text); int port; port = PPORT_BASE; // Datenregister schreiben Out32(port,signal); lbAusgabe->Items->Add("Schreibe: " + IntToStr(signal)); // Zur Überprüfung lesen signal = Inp32(port); lbAusgabe->Items->Add("Lese: " + IntToStr(signal)); lbAusgabe->Items->Add("--------------------"); } //--------------------------------------------------------------------------- void __fastcall TForm1::btLesenClick(TObject *Sender) { short signal; int port; for(port=PPORT_BASE; (port<(PPORT_BASE+8)); port++) { signal = Inp32(port); lbAusgabe->Items->Add("Lese: " + IntToStr(signal)); } lbAusgabe->Items->Add("--------------------"); }
Den Code habe ich so aus einer Konsolenanwendung die als Beispiel für den Umgang mit der DLL erstellt wurde genommen und eben leicht abgeändert, dass ich daraus ne GUI-Anwendung machen kann.
Diese Pins müsste ich ja eigentlich als Eingänge verwenden können:
10 – Acknowledge
11 – Busy
12 – Paper Empty
13 – Selected
15 – Error (invertiert)Als Eingänge verwenden kann ich die, wenn ich 3,5 – 5V Gleichspannung anlege, hab ich gelesen.
Nun meine Fragen:
- Wie genau lese ich diese Pins aus?
- Bei dem Button zum Lesen ist eine Schleife, die 8 Werte ausliest. Der erste ist der, den ich auch mit dem anderen Button schreiben kann. Für was sind die anderen Werte?
- Kann ich wirklich einfach mit 5 V / DC auf so einen Pin oder muss ich da noch irgendwas beachten? (Also irgendwie ne Schutzdiode oder was auch immer ...)Schon mal Danke für die Antworten!
Gruß
RADS
-
Werde dir erstmal klar, wie die Signale an den PC gesendet werden sollen. Es gibt mehrere Möglichkeiten:
Wenn Datenleitungen benutzt werden, kannst du einfach mit Inp32 die Daten lesen. Damit wäre die Forderung breits erfüllt.
Wenn Steuerpins gesetzt werden, müssen diese extra abgefragt werden. Das wird von deiner DLL nicht unterstützt und du mußt direkt mit WinAPImethoden drauf zugreifen. Wahrscheinlich mit DeviceIoControl(). Du mußt nur noch die korrekte Funktion (die an DeviceIoControl übergeben wird) rausfinden, um den Pinstatus abzufragen. Im Source der DLL steht übrigens ein Beispiel für DeviceIoControl.
-
Morris Szyslak schrieb:
Werde dir erstmal klar, wie die Signale an den PC gesendet werden sollen. Es gibt mehrere Möglichkeiten:
Wenn Datenleitungen benutzt werden, kannst du einfach mit Inp32 die Daten lesen. Damit wäre die Forderung breits erfüllt.
Wenn Steuerpins gesetzt werden, müssen diese extra abgefragt werden. Das wird von deiner DLL nicht unterstützt und du mußt direkt mit WinAPImethoden drauf zugreifen. Wahrscheinlich mit DeviceIoControl(). Du mußt nur noch die korrekte Funktion (die an DeviceIoControl übergeben wird) rausfinden, um den Pinstatus abzufragen. Im Source der DLL steht übrigens ein Beispiel für DeviceIoControl.
Also das mit den WinAPImethoden muss ich mir erst mal anschauen ... hört sich aber kompliziert an ...
Am besten wäre es schon die Steuerpins zu benutzen. Wenn nicht nehme ich halt 5 von den Datenpins als Ausgänge und 3 als Eingänge - wäre aber keine so gute Lösung ...
Wie wäre es eigentlich dann, wenn ich 5V drauf gebe (also 1) und dann ne 0 auf den Pin schreibe?
Und geht das Auslesen der anderen Pins nicht einfach über ne bestimmte Adresse ... das könnte doch an sich auch der Grund für diese komische Schleife sein beim Lesen-Button ...
-
Ich habs gelöst! Es geht doch sehr einfach. (Wäre
vielleicht auch was für die FAQ ...)
Also es ist so:
Man muss nur ne andere Adresse nehmen. Das hier sinddie Adressen der einzelnen Register (hex):
LPT1:
Data-Register: 0378
Status-Register: 0379
Control-Register: 037aLPT2:
Data-Register: 0278
Status-Register: 0279
Control-Register: 027aUnd damit kann man dann auf immer die gleiche Art und
Weise Daten lesen und schreiben. Die Pins fürs
Data-Register kann man als Ein- oder Ausgänge nehmen,
das Control-Register nur als Ausgang und das
Status-Register nur als Eingang. Die restlichen Pins
sind alle Masse.
Dabei sind es immer Signale zwischen 3,5 bis maximal
5V. Der Strom sollte möglichst nicht höher als 5mA
sein - mit 10mA sollte es aber angeblich auch noch
gehen. Also am besten verwendet man eine Treiberstufe
und zieht damit ein Relais an - je nachdem was man
ansteuern will. Das mit dem Relais hat halt noch den
Vorteil einer galvanischen Trennung, so das das Ganze
sicherer ist.
Hier noch die Pinbelegungen:
http://logix4u.net/parallel.gifInfos zu all dem findet man auf:
http://logix4u.net/Dort gibt es auch die notwendige inpout32.dll zum
Download.
Hier noch Beispiele wie man diese DLL verwendet:
1. windows.h einbinden Basisaderesse definieren
#include <windows.h> #define PPORT_BASE 0x378
(Bei den anderen halt immer eins dazu und falls LPT2
auch verwendet wird noch eine Definition dafür)
2. DLL einbinden und Prozessadressen laden
// DLL laden HINSTANCE hLib = LoadLibrary("inpout32.dll"); // Prozessadressen laden inp32fp = (inpfuncPtr) GetProcAddress(hLib, "Inp32"); oup32fp = (oupfuncPtr) GetProcAddress(hLib, "Out32");
3. Funktionsprototypen, Pointer und Wrapper
erstellen
// Funktionsprototypen typedef short (_stdcall *inpfuncPtr)(short portaddr); typedef void (_stdcall *oupfuncPtr)(short portaddr, short datum); // Pointer inpfuncPtr inp32fp; oupfuncPtr oup32fp; // Wrapper-Funktionen short Inp32(short portaddr) { return (inp32fp)(portaddr); } void Out32(short portaddr, short datum) { (oup32fp)(portaddr,datum); }
Jetzt könnt ihr die DLL verwenden
Schreiben:
short signal = 100; int port; port = PPORT_BASE; // Datenregister schreiben Out32(port, signal); // Zur Überprüfung lesen signal = Inp32(port); cout << signal;
Lesen:
short signal; int port; signal = Inp32(PPORT_BASE); cout << "Data: " << signal << endl; signal = Inp32(PPORT_BASE+1); cout << "Status: " << signal << endl; signal = Inp32(PPORT_BASE+3); cout << "Control: " << signal << endl;
Damit sollte es jetzt wirklich jeder schaffen etwas
über den PC anzusteuern.
Viel Spaß damit!
Gruß
Dominik
-
Hi,
(die lezten 3h wahren sehr lehrreich)
ich habe zwar nicht so die ahnung aber für alle die einen
- error C2664
- error C2664 'LoadLibraryW'
- Konvertierung des Parameters 'const char in 'LPCWSTR' nicht möglich
oder änliches erzeugen sollten
hier die lösung
anstatt
HINSTANCE hLib = LoadLibrary("inpout32.dll");das hier benutzen
HINSTANCE hLib = LoadLibrary(L"inpout32.dll");wichtig ist das L dabei
ich weis zwar nicht was das bedeutet aber es gehtsollte jemand wissen was dieses L macht ich würde mich freuen was dazu zu lernen.
damit mich hier nicht alle für zurückgeblieben halten, ich habe vorgestern mit c++ angefangen und kenne mich mit dieser materie noch fast garnicht aus.
dies ist mein programmansatz (sinnvoll zusammengeklaut)
#include <windows.h>
#include <iostream>
using namespace std;#define PPORT_BASE ((short) 0x378)
typedef short (_stdcall *inpfuncPtr)(short portaddr);
typedef void (_stdcall *oupfuncPtr)(short portaddr, short datum);inpfuncPtr inp32fp;
oupfuncPtr oup32fp;short Inp32 (short portaddr)
{
return (inp32fp)(portaddr);
}
void Out32 (short portaddr, short datum)
{
(oup32fp)(portaddr,datum);
}int main()
{HINSTANCE hLib;
hLib = LoadLibrary(L"inpout32.dll");
if (hLib == NULL) {
fprintf(stderr,"LoadLibrary Failed.\n");
return -1;
}inp32fp = (inpfuncPtr) GetProcAddress(hLib, "Inp32");
if (inp32fp == NULL) {
fprintf(stderr,"GetProcAddress for Inp32 Failed.\n");
return -1;
}oup32fp = (oupfuncPtr) GetProcAddress(hLib, "Out32");
if (oup32fp == NULL) {
fprintf(stderr,"GetProcAddress for Oup32 Failed.\n");
return -1;
}short signal = 100;
int port;port = PPORT_BASE;
// Datenregister schreiben
Out32(port, signal);// Zur Überprüfung lesen
signal = Inp32(port);
cout << signal<<endl;// short signal;
// int port;signal = Inp32(PPORT_BASE);
cout << "Data: " << signal << endl;
signal = Inp32(PPORT_BASE+1);
cout << "Status: " << signal << endl;
signal = Inp32(PPORT_BASE+3);
cout << "Control: " << signal << endl;
/*short x;
short i;/* Try to read 0x378..0x37F, LPT1: /
/
for (i=PPORT_BASE; (i<(PPORT_BASE+8)); i++)
{x = Inp32(i);
printf("Port read (%04X)= %04X\n",i,x);
}
*/FreeLibrary(hLib);
return(0);
}
-
Habe alles genauso gemacht. Sobald ich aber einen Wert nach LPT schieben will, erscheint die Fehlermeldung " privilegierte Anweisung "!
Kann mir hierzu jemand helfen???(Das ganze unter WinXP)
-
Hallo
wichtig ist das L dabei
ich weis zwar nicht was das bedeutet aber es gehtDas L bedeutet das das String-Literal nicht als ASCII-String sondern als Unicode-String interpretiert wird. Das du das braucht liegt daran das du wie Unicode-Variante von LoadLibrary benutzt.
Habe alles genauso gemacht. Sobald ich aber einen Wert nach LPT schieben will, erscheint die Fehlermeldung " privilegierte Anweisung "!
Kann mir hierzu jemand helfen???Ja die Forumssuche.
bis bald
akari
-
Habe die Funktionalität wie beschrieben in eine Klasse gekapselt. Trotzdem kommt der gleiche Fehler " privilegierte Anweisung "!
Liegt es vielleicht am SP2 von WinXP?
-
Also ich hab mich neulich auch ma damit befasst und eine Klasse dafür geschrieben
ich glaub, ich hau die hier aml rein^^typedef void _stdcall (*oupfuncPtr)(short portaddr, short datum); typedef short _stdcall (*inpfuncPtr)(short portaddr); //typedefs für die funktionen class IOclass //die eigentliche Klasse { private: short defaddr; //default portadresse HANDLE dll; //handle zur DLL oupfuncPtr out2; //"Rohfunktion" schreiben inpfuncPtr inp2; //"Rohfunktion" lesen public: IOclass()//default konstruktor { dll=LoadLibrary("inpout32.dll");//starte mit dll initalisierung und zuweisung der funktionen inp2 = (inpfuncPtr) GetProcAddress(dll, "Inp32");//private weil nur von klasse genutzt/extern sin andere funksionen erstellt^^ out2 = (oupfuncPtr) GetProcAddress(dll, "Out32");//s.o. if(!dll||!inp2||!out2)Application->Terminate(); //fertig defaddr=0x378;//setze standart portadresse auf Datenregister LPT1 (evtl anpassen) } IOclass(short port) //zweiter Konstruktor mit angabe der Default Portadresse(damit man z.B. 1 Klasse für data und ne zweite für das Kontrolregister hat.) { IOclass();//rufe default Konstruktor auf (um speichereffizient das ganze ncih nochmal schreibn zu müssen^^) defaddr=port; //und setze schließlich die Defaultadresse der Klasse auf die Eingabe } //hier wirds dann interressant void out(short addr, short pins)//zusätzliche angabe der {out2(addr,pins);}//gebe pins an die angegebene Adresse aus short inp(short addr)//einlesen mit adressangebe {return inp2(addr);}//lese ein void out(short pins)//default ausgabefunktion nur pins angeben, adresse wird default genommen { out2(defaddr,pins); } short inp()//hier genauso {return inp2(defaddr);} ~IOclass()//und das Ganze im Destruktor wieder zerstören^^ {FreeLibrary(dll);} };
so ich hab das jez orntlich durchkommentiert und hoffe dass das verständlich ist/bleibt^^
das kompiliert bei mir mit BCB6 Personal fehlerfrei. :xmas1:
hoffe, konnte helfn^^Ele