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 sind

    die Adressen der einzelnen Register (hex):
    LPT1:
    Data-Register: 0378
    Status-Register: 0379
    Control-Register: 037a

    LPT2:
    Data-Register: 0278
    Status-Register: 0279
    Control-Register: 027a

    Und 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.gif

    Infos 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 geht

    sollte 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 geht

    Das 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


Anmelden zum Antworten