I2C - LCD/Tastatur

 

 

 


Ein-Ausgabe zum LCD/Tastatur - Funktionsmodell


 

 

 






 

Software-Interrupt aus ..

Bezeichnung ..

Parameter ..

 


I2C API

I2C Init

int AAh, AH= 80h



I2C API

I2C Scan

int AAh, AH= 81h


 

I2C API

I2C Transmit

int AAh, AH= 82h

 


I2C API

I2C Release

int AAh, AH= 84h



TCP/IP API

API sleep

int ACh, AH= 09h


 

 

 





Ziel-Hardware:
Jeder dESµ SC12-Server, bei dem über den I2C-Bus das I2C-LCD/Tastatur Funktionsmodell angeschlossen ist.
Bei diesem Funktionsmodell wurden eine Telefon-Tastenmatrix und eine LCD-Anzeige über zwei PCF8574 Bausteine am I2C-Bus angeschlossen.

Beschreibung:
Dieses Programm initialisiert den I2C-Bus, dann die LCD-Anzeige, um hernach Tastatureingaben an der LCD-Anzeige auszugeben. Die Tastatur-Scanfunktion wurde um eine Autorepeat-Option erweitert, die LCD-Anzeige kann nicht mehrfach initialisiert werden.

Die Abfragegeschwindigkeit der Tastenmatrix wird durch die API-Funktion sleep() verringert. Das macht es anderen Programmen des Multitask-Betriebssystems möglich, ebenfalls Rechenzeit zu erhalten.









// LCDtast.CPP
// -----------    Version 18.10.2003
//                Borland IDE C++ 3.1 oder 5.2
//                Model: SMALL
//                char:  unsigned
//                bearbeitet: BBS WiLu, D.Schwarzer
// -----------------------------------------------------
// Ziel-Hardware: jeder dESµ SC12 bei dem am I2C-Bus das
// I2C-LCD/Tastatur Funktionsmodell angeschlossen ist.

// Funktion: Das Programm fragt die 3 x 4 Telefon-
// Tastenmatrix der Platine ab und sendet die Eingaben
// zur LCD-Anzeige

// Tastatur: Signale am PCF8574 Tor 0x4C
//       TorBit:   7   6  5  4   3  2  1  0
//       LcdPin:  led  s3 s2 s1  z4 z3 z2 z1
// LCD: Signale am PCF8574 Tor 0x4E
//       8574 TorBit:      7  6  5  4   3  2  1  0
//       Pin an der Lcd:  nc RS RW  E  D7 D6 D5 D4


#define i2c_tast  0x4C   // Adr: PCF8574 Tor 6, Tastatur
#define i2c_lcd   0x4E   // Adr: PCF8574 Tor 7, LCD

#define OFF 0            // LED einschalten
#define ON  1            // LED ausschalten


#include <stdio.h>
#include <dos.h>

static union  REGS  inregs;
static union  REGS  outregs;

// -------------------------------------------------------
// SoftINTs des I2C-Bus am SC12

void i2c_init(void)
{
 inregs.h.ah = 0x80;
 int86(0xAA,&inregs,&outregs);
}
void i2c_release(void)
{
 inregs.h.ah = 0x84;
 inregs.h.al = 0;
 int86(0xAA,&inregs,&outregs);
}
int i2c_scan( int start_addr, int end_addr)
{
 inregs.h.ah = 0x81;
 inregs.h.al = start_addr;
 inregs.h.cl = end_addr;
 int86(0xAA,&inregs,&outregs);
 return (outregs.h.al);
}
int i2c_transmit(char slave, char c)
{
 inregs.h.ah = 0x82;
 inregs.h.al = slave & 0xFE;
 inregs.h.cl = c;
 int86(0xAA,&inregs,&outregs);
 if(outregs.x.flags & 0x01){
  return (int)outregs.h.al & 0x00FF;
 }
 return(0);
}
int i2c_receive (char slave, char* c, char lastchar)
{
 inregs.h.ah = 0x82;
 inregs.h.al = slave | 0x01;
 if(lastchar)inregs.h.cl = 1; // mehrere Zeichen holen
 else        inregs.h.cl = 0; // nur ein Zeichen holen
 int86(0xAA,&inregs,&outregs);

 if(outregs.x.flags&0x01){
  *c = 0;
  return (int)outregs.h.al & 0x00FF;
 }
 *c = (char)outregs.h.ch;
 return(0);
}

void api_sleep(int ms)
{
 inregs.x.ax = 0x0900;
 inregs.x.bx = ms;
 int86(0xAC, &inregs, &outregs);
}

// -------------------------------------------------------
// cmdout()
// zum Senden eines Kommandos müssen RS=0 und RW=0 sein.
// Das Commando wird in zwei Halbbytes zerlegt. -E=0 / E=1
void cmdout (char c)
{ int hb=c>>4, lb=c&0x0F;        // DatenByte zerlegen
                                 // High HalbByte senden
  i2c_transmit(i2c_lcd,0x10+hb); // -RS -RW  E  h h h h
  i2c_transmit(i2c_lcd,0x00+hb); // -RS -RW -E  h h h h
                                 // Low  Halbbyte senden
  i2c_transmit(i2c_lcd,0x10+lb); // -RS -RW  E  l l l l
  i2c_transmit(i2c_lcd,0x00+lb); // -RS -RW -E  l l l l
  i2c_release();
  if (c==0x01) api_sleep(5);     // bei Clear Display
}

// lcd_init()
// Initialisiert ein Display mit 20 Spalten und 4 Zeilen
// sowie einer 4*7 Zeichenmatrix auf den Betrieb mit einem
// 4Bit-Datenbus. Ein Byte wird in diesem Fall in der Form
// zweier Halbbytes gesendet

// RS=1, Daten übertragen,  RS=0, Kommando übertragen
// RW=1, vom HD44780 lesen, RW=1, zum HD44780 schreiben
// E     Der HD44780 übernimmt das Datum, wenn E von 1->0
//       fällt
// D7-D4 Datenleitungen für Halbbytes.

// Die Initialisierung erfolg nach den Vorschriften und
// Zeitvorgaben des Datenblattes. Sie unterbleibt, wenn
// TorBit 7 auf 0 gesetzt ist.

void lcd_init (void)
{
 int time[]= {15,5,1,0}, n=0;
 char torbyte[]={0xFF};

 i2c_receive(i2c_lcd,torbyte,0); // TorBit 7 lesen
 i2c_release();
 if (*torbyte<0x80){
   cmdout(0x01);                 // Clear Display
   return;                       // LCD ist initialisiert
 }

 i2c_transmit(i2c_lcd,0x03);     // -RS -RW -E  0 0 1 1
 do{
    api_sleep (time[n++]);
    i2c_transmit(i2c_lcd,0x13);  // -RS -RW  E  0 0 1 1
    i2c_transmit(i2c_lcd,0x03);  // -RS -RW -E  0 0 1 1
    i2c_release();
  } while (time[n]!=0);

 i2c_transmit(i2c_lcd,0x12);     // -RS -RW  E  0 0 1 0
 i2c_transmit(i2c_lcd,0x02);     // -RS -RW -E  0 0 1 0

 cmdout(0x28);             // 2 Zeilen, 5*7 Zeichensatz
 cmdout(0x0F);             // Displ.on, Curs.on, Blink.on
 cmdout(0x01);             // Clear Display
}

// chrout()
// zum Senden von Daten müssen RS=1 und RW=0 sein.
// Die Daten werden in zwei Halbbytes zerlegt. -E=0 / E=1
void chrout (char c)
{
 int hb=c>>4,lb=c&0x0F;            // DatenByte zerlegt
                                   // High HalbByte senden
 i2c_transmit(i2c_lcd,0x50+hb);    //  RS -RW  E  h h h h
 i2c_transmit(i2c_lcd,0x40+hb);    //  RS -RW -E  h h h h
                                   // Low HalbByte senden
 i2c_transmit(i2c_lcd,0x50+lb);    //  RS -RW  E  l l l l
 i2c_transmit(i2c_lcd,0x40+lb);    //  RS -RW -E  l l l l
 i2c_release();
}

// stringout()
// Sendet einen nullterminierten String zur LCD-Anzeige.
// Die Bytes des Strings werden on Halbbytes zerlegt und
// gesendet.
// Die Frequenz des I2C-Bus schein so gering zu sein,
// dass die Übertragung eines Zeichens mehr als 120µs
// benötigt. Damit wird die Abfrage des Busy-Flags
// überflüssig. -E=0 / E=1

void stringout (char *c)
{
 int n=0;
 do{
  chrout(c[n]);
 } while (c[++n]!=0);
}

// -----------------------------------------------------
// TastInit()
// setzt alle Bits des Tastaturtores auf log1. Dadurch
// können externe Eingabequellen das Tor auf log0 her-
// unterziehen. Diese Initialisierung ist nur notwendig,
// wenn die Gefahr besteht, dass auf einem der Eingänge
// zuvor eine log0 ausgegeben wurde. Dies sollte
// normalerweise nicht eintreten.
// So wird diese Funktion hier nicht benutzt
void TastInit(void)
{
 i2c_transmit(i2c_tast, 0xFF);
}

// led()
// schaltet die LED ein (status=1) oder aus (status=0).
// Hardwaremässig bedingt, besitzt die LED ein inver-
// tiertes Verhalten.
void led(int status)
{
 static char c=0xFF;
 i2c_receive (i2c_tast,&c,0);
 i2c_release();
 if (status) i2c_transmit(i2c_tast, c&0x7F);  // ein
 else        i2c_transmit(i2c_tast, c|0x80);  // aus
 i2c_release();
}

// ScanToAscii()
// übersetzt den Tastatur-Scancode in ASCII-Code. Diese 
// Tabelle kann entfallen, wenn direkt mit den Scancodes
// gearbeitet werden soll. Dies ist bei der hier
// vorliegenden, sehr kleinen Matrix kein Nachteil.
char ScanToAscii (char scan)
{
 switch (scan){
   case 0x37: return('1');
   case 0x57: return('2');
   case 0x67: return('3');
   case 0x3B: return('4');
   case 0x5B: return('5');
   case 0x6B: return('6');
   case 0x3D: return('7');
   case 0x5D: return('8');
   case 0x6D: return('9');
   case 0x3E: return('*');
   case 0x5E: return('0');
   case 0x6E: return('#');
  }
  return(0);
}

// ScanTast()
// scannt die Tastaturmatrix einmal und kehrt zurück.
// Wird hierbei eine gedrückte Taste gefunden, wird diese
// nach 10ms erneut gelesen, dann ihr Code zurückgegeben
// (Tastenentprellung).
// Ein länger anhaltender Druck auf eine Taste führt zu
// Wiederholfunktion 
// Die LED leuchtet, wenn eine Taste gedrückt wird.
// Damit andere Programm noch Ausführungszeit erhalten,
// wird pro Durchlauf eine Zeit von 30ms gewartet.

// Rückgabe:  0 = keine Taste gefunden
//           !0 = ASCII-Code der Tasten

int ScanTast(void)
{
 static char LastHit=0, rep=0;
 char c=0, t=0, h=0, z[]={0x3F,0x5F,0x6F,0x00}, n=0;

 led(OFF);
 i2c_receive (i2c_tast,&c,0);       // status lesen
 i2c_release ();
 // die Schleife setzt die Spaltentorbits s1,s2,s3
 // und vergleicht, ob in den Zeilen ein Wert!= 1111b
 // enthalten ist
 do{
    i2c_transmit(i2c_tast,(c&0x8F)|z[n]); // zeile setzen
    i2c_release();
    i2c_receive (i2c_tast,&t,0);    // status lesen
    i2c_release ();
    t=t&0x7F;                       // LED-Bit ausmaskiert
    if((t&0x0F)==0x0F) n++;         // kein Tastendruck
    else {                          // ein Tastendruck ..
      if (t==LastHit){              // .. gleich wie zuvor
      rep++;
      if (rep<=30){                 // 30*30ms warten
       api_sleep(30);
       continue;
      }
      else{
       api_sleep(30);               // dann Repeat
       led(ON);
       return(ScanToAscii(t));
      }
     }
     else{                          // .. neu
      led(ON);
      api_sleep(10);
      i2c_receive (i2c_tast,&h,0);  // 2.mal lesen
      i2c_release();
      h=h&0x7F;                     // LED-Bit ausmaskiert
      if (h==t){
       LastHit=h; rep=0;
       return(ScanToAscii(h));
      }
     }
    }
 } while (z[n]!=0);

 api_sleep(30);                    // max.angenehm
 LastHit=0;
 return(0);
}


// Testprogramm zu LCDtast.EXE
// ----------------------------
// Initialisiert den I2C-Bus und die LCD-Anzeige. Holt
// dann Tastatureingaben und überträgt diese zur LCD-
// Anzeige.
// Achtung: Nachdem die LCD-Anzeige initialisiert wurde,
// kann Sie kein zweites Mal initialisiert werden. Es sei
// denn, ihre Spannungsversorgung wurde unterbrochen.
 
void main (void)
{
 char  ascii=0;
 char* text="www.GoBlack.de      "
            " LCD/Tastatur Modell"
            " -------------------";

 printf("\r\n LCDTast [Start]\r\n");

 i2c_init();        // I2C-Bus initialisieren
                    // Test ob I2C-Bus i.o.
 if(i2c_scan(i2c_tast, i2c_tast)!=i2c_tast){
  i2c_release();
  printf ("PCF8574 der Tastatur nicht gefunden");
  return;
 }
 if(i2c_scan(i2c_lcd, i2c_lcd)!=i2c_lcd){
  i2c_release();
  printf ("PCF8574 der LCD nicht gefunden");
  return;
 }

 lcd_init();        // LCD initialisieren
 stringout(text);
 stringout(" [START] ");

                    // Tastendruck holen bis # gedrückt
 do{
  ascii =ScanTast();
  if(ascii!=0){
   chrout(ascii);
   printf("%c",ascii);
  }
 } while (ascii!='#');

 cmdout(0x01);      // LCD löschen
 stringout(text);
 stringout("             [ENDE]");
 i2c_release();
 printf("\r\n LCDTast [Ende]\r\n");
}

 


 

 

 

 


Hinweise zum Programm

Das vorliegende Programm fasst die Testprogramme zur Initialisierung der LCD-Anzeige und der Tastatur zusammen. Mit ihm kann das Zusammenspiel beider Geräte nachvollzogen werden. Dabei ist zu bemerken, dass die LCD-Anzeige, ihre Zeilen in der Abfolge 1,3,2,4 füllt. Ein Umstand, der bei umfangreichen Ausgaben mit scrollendem Text ein Nachdenken über die Cursorführung erforderlich macht.

Zudem verhindert die Abfrage von Torbit 7 der LCD-Anzeige, eine Mehrfach-Initialisation der Anzeige. Dieses Programm kann also beliebig oft gestartet werden, ohne dass die LCD-Anzeige spannungslos gemacht werden muss.

Der Funktionsablauf hierfür basiert auf der Erkenntnis, dass das unbenutzte Bit7 der LCD-Anzeige, nach dem Anlegen der Betriebsspannung den Zustand log1 annimmt. Im Verlauf der Initialisierung der LCD-Anzeige wird es auf log0 gesetzt. Dieser Zustand bleibt bestehen, bis die Spannung abgeschaltet wird. Ist Bit7 des Torbausteins PCF 8574 an der LCD-Anzeige also log1 wurde diese gerade eingeschaltet, und die Anzeige muss initialisiert werden. Bei log0 muss die Anzeige noch vom vorhergehenden Betrieb initialisiert sein.


 

 

 

 


  zip.Download

 

GoBlack [18.10.2003]