Autor Beitrag
Taxi4110
Hält's aus hier
Beiträge: 9



BeitragVerfasst: Di 03.01.06 14:57 
Hallo Jungs und Mädels,

heute will ich euch zeigen, wie Ihr mit Hilfe des .NET Frameworks unc C# ein Lcd über den LPT-Port ansteuern könnt. Als erstes brauchen wir natürlich ein paar Sachen:
- Ein LCD mit HD44780 kompatiblen Controller
- Druckerkabel das wir "zerlegen" :D
- Potentiometer 10k
- Strom :D
- etwas Geduld und eine ruhige Hand

Ich hab mir für meine Zwecke ein WD-C2704M-1HNN LCD von Pollin Elektronik geholt. Darauf kann man 4x27 Zeichen darstellen und kostet NUR 4,95 € --> www.pollin.de
user defined image

An dieser Stelle möchte ich anmerken, dass es mir bei diesem Artikel mehr um die Programmierung geht, als auf den Hardware-Umbau! Trotzdem werde ich dies kurz erläutern.

Mit dem Display kommt dementsprechend die Anschlußbelegung:
user defined image
user defined image
Ich habe in mehreren Foren gelesen, dass je nachdem welche software ihr benutzt, pins vertauschen sollt bzw. es im 4bit Modus benutzen sollt. Schmarn! Wenn ich schon eine 8Bit Ansteuerung habe! Außerdem bauen wir uns ja hier unser Programm selber. An dieser Stelle nochmal MERCI an die Delphi User im Forum, die mir den Delphi-Source erläutert haben.

Solltet ihr alles richtig angelötet haben, schaut das ganze ungefähr so aus:
user defined image
Wichtig: auf Pin3 den Schleifer vom Poti, um den Kontrast des Displays einzustellen!
user defined image

Den Strom hole ich mir vom Netzteil --> 5V. Wenn Ihr alles richtig gemacht habt, dann stecker an den lpt-port und Strom ans Display. Dann solltet Ihr folgendes auf dem LCD sehen:
user defined image
Die zwei scharzen Balken zeigen, das beide Controller des Displays (ja, es hat zwei!! controller) laufen und Strom haben. Soweit, so gut!

Kommen wir zum wichtigen Teil - Wir programmierung uns eine Applikation zur Ansteuerung des Disp.

So, bevor wir starten haben wir noch ein kleines Problem. Ab WinNT ist es leider nicht mehr so einfach, Daten über den LPT-Port zu schicken. Dafür brauchen wir noch eine .dll, die inpout32.dll. ---> www.logix4u.net/inpout32.htm

Jenachdem welche IDE ihr benutzt, legt ihr als erstes ein neues Projekt an bzw. erstellt euch eine .cs Datei. Wir fangen mit dem einbinden der inpout32.dll an:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
using System.Threading;
using System.Runtime.InteropServices; // brauchen wir um eine dll einzubinden

public class LptAccess
  {
    /* For sending to the ports */
    [DllImport("inpout32.dll", EntryPoint = "Out32")]
    public static extern void Output(int adress, int val);
    /* For receiving from the ports */
    [DllImport("inpout32.dll", EntryPoint = "Inp32")]
    public static extern int Input(int adress);
  }

Wie ihr seht habe ich die Funktionen in einer extra Klasse abgelegt, der Übersicht halber! Über Output können wir über den lpt senden. Als nächstes folgen die Funktionen, um Einstellungen und Daten in das LCD zu schreiben. Erst noch ein paar Variablen...
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
public class Form1 : System.Windows.Forms.Form
{
  // Hier werden die LPT-Ports definiert
  private const int control = 890, data = 888;
  // Variable um später zu prüfen, ob LCD initialisiert ist
  private bool is_initialised = false;
  // Array mit allen Zeichenadressen
  private int[] cCharAdr = { 00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 };
  // Array für entsprechenden Controller
  private int[] cCharCtrl = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };

So, ihr braucht jetzt nicht verzweifeln und euch fragen was das für Arrays sind. Ist im Prinzip ganz einfach... Jedes Zeichen das Ihr auf dem Display darstellen wollt, bekommt ja eine gewisse Adresse z. B. bei dem Namen "Taxi" soll das T an die erste Stelle, a an die zweite... usw. Dafür brauchen wir das cCharAdr Array. Ihr seht das aber alles noch im kompletten Source. Da ist es noch einfacher zu verstehen!
Da das Display ja zwei Controller hat, ist ein Controller für die obere, der andere für die untere Display Hälfte zuständig. Dafür ist das cCharCtrl da. Mit dem Array prüfen wir, welchen Controller wir ansteuern müssen, um ein Symbol an eine bestimmte Stelle zu schreiben.
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
private void WriteDirect(int no)
  {
    switch (no)
    {
      case 0:
        LptAccess.Output(data, 56);
        LptAccess.Output(control, 8+0+2+1);
        LptAccess.Output(control, 8+0+2+0);
        LptAccess.Output(control, 8+0+2+1);
        break;
      case 1:
        LptAccess.Output(data, 56);
        LptAccess.Output(control, 8+0+2+1);
        LptAccess.Output(control, 0+0+2+1);
        LptAccess.Output(control, 8+0+2+1);
        break;
      default:
        // alles andere interessiert uns nicht
        break;
    }
  }
  private void WriteCtrl(int cdisp, int no)
  {
    switch (no)
    {
      case 0:
        Thread.Sleep(3);
        LptAccess.Output(data, cdisp);
        LptAccess.Output(control, 8+0+2+1);
        LptAccess.Output(control, 8+0+2+0);
        LptAccess.Output(control, 8+0+2+1);
        break;
      case 1:
        Thread.Sleep(3);
        LptAccess.Output(data, cdisp);
        LptAccess.Output(control, 8+0+2+1);
        LptAccess.Output(control, 0+0+2+1);
        LptAccess.Output(control, 8+0+2+1);
        break;
      default:
        break;
    }
  }
  private void WriteData(int cdisp, int no)
  {
    Thread.Sleep(3);
    switch (no)
    {
      case 0:
        LptAccess.Output(data, cdisp);
        LptAccess.Output(control, 8+0+0+1);
        LptAccess.Output(control, 8+0+0+0);
        LptAccess.Output(control, 8+0+0+1);
        break;
      case 1:
        LptAccess.Output(data, cdisp);
        LptAccess.Output(control, 8+0+0+1);
        LptAccess.Output(control, 0+0+0+1);
        LptAccess.Output(control, 8+0+0+1);
        break;
      default:
        break;
    }
  }

Jetzt geht es ans eingemachte: Wir haben hier drei Funktionen WriteDirect, WriteControl und WriteData. In jeder Funktion ist ein switch eingebaut. 0 steht für den ersten Controller, 1 für den zweiten. Außerdem seht ihr, dass ich an bestimmten stellen einen Thread.Sleep eingefügt habe. Das ist wichtig, denn sonst könnte es zu Überschneidungen der Befehle kommen, falls euer LCD nicht so schnell reagieren kann -> Stichwort: Busyflag! Jetzt fragt Ihr euch natürlich, was da für komische Zahlen übermittelt werden... ganz einfach... werfen wir einen Blick in die Dokumentation des LCD:
user defined image
Schaut kompliziert aus... ist es aber nicht :) Ich erläutere euch das an einem Beispiel: Wir wollen das Display einschalten und den Cursor blinken lassen. Schauen wir in der Zeile, wo der Befehl "Display on/off" steht. Wir müssen also BIN 1101 -- AN AN AUS AN an das Display senden. Also schnell umrechnen in Dezimal bin:1101 = dez:13. Heißt, wir übertragen dez:13 an das LCD über den entsprechenden Port und das Disp führt unsere Funktion aus. Jetzt könnt ihr ja selber sehen, was für Daten bei den Befehlen gesendet werden. Natürlich ist jedes Display anders aber das Prinzip ist das selbe!
Endspurt: Es fehlen uns noch zwei wichtige Funktionen. Einmal um das Display zu initialisieren und eine Funktion um einen beliebigen Text an das Display zu übertragen.

Bevor auf das Display geschrieben werden kann, muss es immer zuerst initialisiert werden:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
private void Prepare_LCD(object sender, System.EventArgs e)
  {
    WriteDirect(0);
    WriteDirect(1);
    Thread.Sleep(5);
    WriteDirect(0);
    WriteDirect(1);
    Thread.Sleep(1);
    WriteDirect(0);
    WriteDirect(1);
    WriteCtrl(1,0); // Clear Display Controller 0
    WriteCtrl(1,1); // Clear Display Controller 1
    WriteCtrl(2,0); // Cursor Home
    WriteCtrl(2,1); // Cursor Home
    WriteCtrl(6,0); // EntryMode = Increment, no shift
    WriteCtrl(6,1); // EntryMode = Increment, no shift
    WriteCtrl(12,0);// Cursor stellen auf Controller1+LCD AN
    WriteCtrl(12,1); // Cursor stellen auf Controller2+LCD AN
    is_initialised = true;
  }

Was genau passiert, könnt ihr einfach aus der Doku weiter oben entnehmen. Wichtige Sachen habe ich nochmal kommentiert. Jedes Display, muss nach einer bestimmten Reihenfolge initialisiert werden. Steht aber auch in der Doku.
So, werfen wir den FormDesigner an:
user defined image
Ich hab hier vier Textboxen auf meiner Form plaziert. Jede TextBox steht für eine Zeile im Display. Ihr könnt das natürlich auch anders regeln. Der Button "Schreibe auf LCD" ruft folgende Funktion auf:
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
    private void Text_to_Display(object sender, System.EventArgs e)
    {
      if(is_initialised == false)
      {
        MessageBox.Show("Display muss erst initialisiert werden!""Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        //is_initialised = true;
      }
      else
      {
        #region Zeile 1
        string line1 = textBox1.Text;
        int c1 = line1.Length;
        // Errechnen der noch übrigen Zeichen der Zeile
        int rest1 = 27 - c1;
        string emptys1 = " ";
        string pholder = "";
        // Wenn die Zeile weniger als 27 Zeichen enthält mit Leerzeichen füllen
        for(int i = 0; i < rest1; i++)
        {
          pholder = pholder + emptys1;
        }
        if(c1 < 27)
        {
          line1 = line1 + pholder;
        }
        #endregion
        #region Zeile 2
        string line2 = textBox2.Text;
        int c2 = line2.Length;
        int rest2 = 27 - c2;
        emptys1 = " ";
        pholder = "";
        for(int i = 0; i < rest2; i++)
        {
          pholder = pholder + emptys1;
        }
        if(c2 < 27)
        {
          line2 = line2 + pholder;
        }
        #endregion
        #region Zeile 3
        string line3 = textBox3.Text;
        int c3 = line3.Length;
        int rest3 = 27 - c3;
        emptys1 = " ";
        pholder = "";
        for(int i = 0; i < rest3; i++)
        {
          pholder = pholder + emptys1;
        }
        if(c3 < 27)
        {
          line3 = line3 + pholder;
        }
        #endregion
        #region Zeile 4
        string line4 = textBox4.Text;
        int c4 = line4.Length;
        int rest4 = 27 - c4;
        emptys1 = " ";
        pholder = "";
        for(int i = 0; i < rest4; i++)
        {
          pholder = pholder + emptys1;
        }
        if(c4 < 27)
        {
          line4 = line4 + pholder;
        }
        #endregion
        // allLines bekommt jetzt alle Zeilen zugewiesen
        string allLines = line1 + line2 + line3 + line4;
        // lsa: Merker für Adresse | lsc: Merker für Controller 
        int lsa = -1int lsc = -1int adr = 0int ctrl = 0;
        for(int z = 0; z < allLines.Length; z++)
        {
          // Adresse des zu schreibenden Zeichens aus Array holen
          adr = cCharAdr[z];
          // Controller holen, der für die Zeichenposition zuständig ist
          ctrl = cCharCtrl[z];
          if(adr < lsa || adr > lsa || ctrl < lsc || ctrl > lsc)
          {
            WriteCtrl(128+adr,ctrl);
            lsa = adr;
            lsc = ctrl;
          }
          // Zeichen umwandeln von Char
          int charCode = convertANSI(allLines[z]);
          // Zeichen in LCD schreiben
          WriteData(charCode, ctrl);
          lsa++;
        }
      }
    }

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
private int convertANSI(char c)
    {
      int result = 0;
      switch (c)
      {
        case 'ä':
          result = 225;
          break;
        case 'ö':
          result = 239;
          break;
        case 'ü':
          result = 245;
          break;
        case 'ß':
          result = 226;
          break;
        default:
          result = (int)c;
          break;
      }
      return result;
    }

Ihr lest ja immernoch.. das ist schön :) Ich möchte im kurzen den Ablauf erklären, was passiert, wenn der Button "Schreibe auf LCD" gedrückt wird. Als erstes wird jede TextBox für sich eingelesen und mit Leerzeichen aufgefüllt. Dann wird der Variablen allLines Zeile 1 bis 4 zugewiesen. Der Rest erklärt sich eigentlich von selbst. Jedes Zeichen der Variable allLines wird umgewandelt und dann an das LCD geschickt. Fertig!! :)

Rächtsschraibfeler dürft ihr behalten.

user defined image

//EDIT: Im Anhang hab ich den kompletten Source mit Beispiel, wie Ihr z.B. Uhrzeit auf dem LCD ausgeben könnt.


Moderiert von user profile iconraziel: Topic aus Open Source Projekte verschoben am Di 03.01.2006 um 14:46
Einloggen, um Attachments anzusehen!
cAs70R
Hält's aus hier
Beiträge: 1



BeitragVerfasst: So 26.02.06 01:48 
hey super echt geniales tutorial! super erklärt und daher leicht verständlich!

ich bin zurzeit nämlich so auf den hardware-programmieren trip und da wir sowas in der schule nicht machen, bin ich froh,
über google das board gefunden zum haben :D...

mfg
castor
zumo
Hält's aus hier
Beiträge: 1



BeitragVerfasst: Di 11.07.06 12:43 
Hi, tolles Tutorial. Allerdings hakt es bei mir gerade bei den Prozeduren WriteDirect, WriteCtrl und WriteData.

Kann mir jemand erklären, was bei:
ausblenden C#-Quelltext
1:
2:
3:
LptAccess.Output(control, 8 + 0 + 2 + 1);
LptAccess.Output(control, 8 + 0 + 2 + 0);
LptAccess.Output(control, 8 + 0 + 2 + 1);

usw. passiert bzw. wo die Daten davon hingeschrieben werden? Scheint ja um die Initialisierung/Adressierung der zuvor über LptAccess.Output(data, cdisp); eingegebenen Daten zu gehen.

Und warum werden die Daten so langsam übertragen/dargestellt? Liegt das an der LPT-DLL? Ich schreibe mit folgender Prozedur testweise das ganze Display voll und dies dauert mehrere Sekunden:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
        {
            for (int i = 0; i < 108; i++){

                WriteCtrl(128 + cCharAdr[i], cCharCtrl[i]);
                WriteData((int)'a', cCharCtrl[i]);
             }
             
        }


Moderiert von user profile iconTino: Code- durch C#-Tags ersetzt
lord_fritte
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 27



BeitragVerfasst: Mo 24.12.07 19:37 
bekommt man die inpout32.dll auch für XP? wenn ich das display initalisieren möchte bekomme ich die meldung das ein externes Modul also die inpout32.dll einen Fehler verursacht.
larsss
Hält's aus hier
Beiträge: 1



BeitragVerfasst: Mo 16.06.08 11:57 
kann der threadersteller oder irgend jemand die bilder neu hochladen?
Skiller-1988
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 100

Win XP | Debian | Ubuntu
C# | PHP | VB.NET
BeitragVerfasst: Sa 25.10.08 13:12 
Hi finde das Tutorial auch sehr gut wäre daher dankbar wenn die Bilder irgentwie neu hochgeladen werden könnten.

_________________
~ Wer Rechtschreibfehler findet darf sie behalten ~
Taxi4110 Threadstarter
Hält's aus hier
Beiträge: 9



BeitragVerfasst: Fr 28.11.08 19:35 
Schande über mich. Hab das Tutorial ganz vergessen. Die Bilder gibt es leider nicht mehr :(
KainPlan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 27

Vista Buisness, Windows 7
C/C++, C#, PHP...
BeitragVerfasst: Mi 28.01.09 02:10 
Also ich will ja echt niemandem auf die Füße treten aber: www.codeproject.com/KB/cs/cspplcds.aspx *hust*