|
|
// 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");
}
|
|