#include "com.h" #include "com.c" void main(void) //Hauptprogramm { //RS232 1 Schnittstelle ”ffnen com_open(1,B_38400 | DB_8 | STP_1 | PAR_EVEN , 43); variable_a = com_getc();//Zeichen empfangen com_putc(variable_b);//Zeichen senden //............. } //Anfang com.h /* Datum: 23.10.94 Dateiname: com.h Funktion: Diese Datei ist die Include-Datei fuer den Interrupt- gesteuerten seriellen Schnittstellentreiber und musz mit >> #include "[Laufwerk]:[path]\com.h" << in die jeweilige Programmdatei eingebunden werden. */ extern int com_open(char c, unsigned flags, int bufsize); extern void com_close(void); extern int com_getc(void); extern int com_putc(char c); extern void rts_on(void); extern void rts_off(void); extern char *rx_buf; extern int rx_high, rx_low, rx_rd, rx_wr, rx_len, rts, cts, rx; /* Baudrate */ #define B_110 0 #define B_150 1 #define B_300 2 #define B_600 3 #define B_1200 4 #define B_2400 5 #define B_4800 6 #define B_9600 7 #define B_19200 8 #define B_38400 9 #define B_57600 10 #define B_115200 11 /* Anzahl der Datenbits */ #define DB_5 0x00 #define DB_6 0x10 #define DB_7 0x20 #define DB_8 0x30 /* Anzahl der Stopbits */ #define STP_1 0x00 #define STP_2 0x40 /* Paritaet */ #define PAR_OFF 0x00 #define PAR_ODD 0x80 #define PAR_EVEN 0x180 //Ende com.h //Anfang com.c /* Datum: 23.10.94 Dateiname: com.c Funktion: Diese Datei beinhaltet Funktionen zum interruptgesteuerten Daten-Empfang von der seriellen Schnittstelle. Der Sendtransfer wird ohne Interrupts durchgefuehrt. */ #include #include #include #include #ifdef __cplusplus #define __CPPARGS ... #else #define __CPPARGS #endif void interrupt com_int(__CPPARGS); /* interrupt prototype */ void interrupt (*old_com_int)(__CPPARGS); /* interrupt function pointer */ /****************************** Funktions-Prototypen ************************/ int com_open(char c, unsigned flags, int bufsize); void com_close(void); void rxint(void); void rts_on(void); void rts_off(void); int com_putc(char c); int com_getc(void); int d_i(void); void e_i(void); /****************************** globale Variablen ***************************/ char com; char com_lsr; int portbase, rx_bufsize, rx_high, rx_low, rx_rd, rx_wr, rx_len, rts, cts, rx; char *rx_b; /****************************** com_open() **********************************/ /* UEBERGABEPARAMETER: */ /* char c : COM1 oder COM2 */ /* int flags : XXXXxxxxXXXXxxxx */ /* | |||||||----- Baudrate */ /* | |||||| */ /* | ||||*------- Anzahl der Datenbits */ /* | |||| */ /* | |||*-------- Anzahl der Stopbits */ /* | ||| */ /* | |*---------- Paritaet */ /* | | */ /* *----------------- frei */ /* int bufsize : Ringpuffergroesse */ /* */ /* RETURNWERT: (int) */ /* 0 COM initialisiert */ /* -1 es ist ein Fehler aufgetreten */ /* */ /* KURZBESCHREIBUNG: */ /* Die com_open() Funktion initialisiert die serielle Schnittstelle, */ /* wie dies durch die Uebergabeparameter eingestellt wurde und legt */ /* einen Ringpuffer mit der Groesze bufsize an. Sind Uebergabeparameter */ /* falsch, oder ist nicht genuegend Speicher fuer den Ringpuffer */ /* verfuegbar so wird als Returnwert -1 zurueckgegeben. */ /****************************************************************************/ int com_open(char c, unsigned flags, int bufsize) { unsigned baud; static unsigned baudtab[] = {1047,768,384,192,96,43,24,12,6,3,2,1}; /* Tab.fuer Baudratengenerator */ if (c != 1 && c != 2) return -1; /* falscher Parameter */ com = c; if ((rx_b = (char*)malloc(bufsize)) == NULL) return -1; /* kann Puffer nicht oeffnen */ if (com == 2) /* Basisadresse zuordnen */ portbase = 0x200; else portbase = 0x300; rx_bufsize = bufsize; /* max. Ringpufferlaenge */ rx_high = (int)(bufsize/1,5); /* kritisch -> RTS = 0 */ rx_low = bufsize/4; /* wieder OK. -> RTS = 1 */ rx_wr = rx_rd = rx_len = 0; /* Ringpuffervar. auf 0 setzen */ outp(portbase|0xfc,0x0); /* RTS ruecksetzen */ outp(portbase|0xf9,0); /* alle 8250 INTs sperren */ outp(portbase|0xfc,0x08); /* Interrupt enable */ baud = baudtab[flags & 0xf]; /* Zaehlwert fuer Baudratengen. */ d_i(); /* alle Interrupts sperren */ outp(portbase|0xfb,0x80); /* set dlab = 1 */ outp(portbase|0xf8,baud); /* BAL-Reg. 8255 Baudrate bits */ outp(portbase|0xf9,baud>>8); /* BAH-Reg. 8255 Baudrate bits */ outp(portbase|0xfb,(flags>>4)&0x1f); /* Datenbits, Paritaet, Stopbits*/ if (com == 2) { old_com_int = _dos_getvect(0x0b); /* Adr der alten ISR von COM2 merken */ _dos_setvect(11,com_int); /* neue ISR Adr. eintragen */ outp(0x21,inp(0x21)&0xf7); /* IRQ 3 in 8259 freigeben */ } else { old_com_int = _dos_getvect(0x0c); /* Adr der alten ISR von COM1 merken */ _dos_setvect(12,com_int); /* neue ISR Adr. eintragen */ outp(0x21,inp(0x21)&0xef); /* IRQ 4 in 8259 freigeben */ } outp(portbase|0xf9,0x1); /* 8250 nur RX INTs freigeben */ e_i(); /* Interrupts wieder freigeben */ rts = 1; outp(portbase|0xfc,inp(portbase|0xfc)|0x02); /* RTS = 1 */ com_getc(); /* holt evtl. vorhandenes Zeichen */ return 0; /* Initialisierung OK. */ } /****************************** com_close() *********************************/ /* UEBERGABEPARAMETER: */ /* keine */ /* */ /* RETURNWERT: */ /* keiner */ /* */ /* KURZBESCHREIBUNG: */ /* Die com_close() Funktion sperrt den jeweiligen IRQ im IMR des 8259 */ /* und setzt den INT-Vektor wieder auf die ISR, die vor aufruf von */ /* com_open() aktiv war. */ /****************************************************************************/ void com_close(void) { int i; i = d_i(); /* alle Interrupts sperren */ if (com == 2) { outp(0x2f9,0); /* 8250 INTs sperren */ outp(0x21,inp(0x21)| 8); /* IRQ 3 in 8259 sperren */ // _dos_setvect(13,old_com_int); /* alte ISR Adr. eintragen */ } else { outp(0x3f9,0); /* 8250 INTs sperren */ outp(0x21,inp(0x21)| 0x10); /* IRQ 4 in 8259 sperren */ // _dos_setvect(12,old_com_int); /* alte ISR Adr. eintragen */ } if(i) /* wenn INTs freigegeben waren */ e_i(); /* Interrupts wieder freigeben */ free(rx_b); /* Ringpuffer wieder freigeben */ } /****************************** com_int() ***********************************/ /* UEBERGABEPARAMETER: */ /* keine */ /* */ /* RETURNWERT: */ /* keiner */ /* */ /* KURZBESCHREIBUNG: */ /* Die com_int() Funktion wird durch einen Hardware Interrupt der */ /* seriellen Schnittstelle aufgerufen. Abhaengig vom aufgetretenen */ /* Interrupt, der im IIR-Register des 8250 gespeichert ist, wird die */ /* jeweilige Service-Routine aufgerufen. */ /****************************************************************************/ void interrupt com_int(__CPPARGS) { register unsigned char intno, imask; ++rx; intno = (inp(portbase|0xfa)>>1) & 3; /* IIR-Register von 8250 holen */ d_i(); switch (intno) { case 2 : /* Empfangs-Interrupt */ rxint(); break; case 1 : /* Sende-Interrupt */ break; } com_lsr = inp(portbase|0x9d); imask = inp(portbase|0xf9); outp(portbase|0xf9,0); e_i(); outp(0x20,0x20); /* EOI fuer 8259 ausgeben */ outp(portbase|0xf9,imask); } /****************************** rxint() *************************************/ /* UEBERGABEPARAMETER: */ /* keine */ /* */ /* RETURNWERT: */ /* keiner */ /* */ /* KURZBESCHREIBUNG: */ /* Die rxint() Funktion ist die Service-Routine des Empfang-Interrupts. */ /* Hier wird das empfangene Zeichen in den Ringpuffer geschrieben und */ /* die Uebertragung durch die Handshakeleitung (RTS) gestopt, wenn der */ /* Ringpuffer voll wird. */ /****************************************************************************/ void rxint(void) { register int c; c = inp(portbase|0xf8); /* Zeichen von RxD Reg. lesen */ rx_b[rx_wr] = (char)c; /* Zeichen in Puffer schreiben */ ++rx_len; /* Zeichenzaehler increment */ if((++rx_wr) >= rx_bufsize) /* wenn Schreibindex am Puffer-*/ rx_wr = 0; /* ende ist, dann rx_wr = 0 */ if((rx_len >= rx_high) || (rts == 0)) { rts = 0; outp(portbase|0xfc,inp(portbase|0xfc)&0xfd); /* RTS = 0 */ } } /****************************** com_getc() **********************************/ /* UEBERGABEPARAMETER: */ /* keine */ /* */ /* RETURNWERT: (int) */ /* -1 wenn kein Zeichen im Ringpuffer steht */ /* XX Wert des empfangenen Zeichens */ /* */ /* KURZBESCHREIBUNG: */ /* Die com_getc() Funktion liefert den Wert des Empfangenen Zeichens . */ /* auf das der Lesezeiger der Ringpuffer-Steuerung gerade zeigt, oder */ /* -1 wenn kein Zeichen im Ringpuffer ist. Weiters wird durch diese */ /* Funktion die Handshakeleitung (RTS) wieder gesetzt, wenn der */ /* Ringpuffer wieder genuegend freien Seicher aufweiszt. */ /****************************************************************************/ int com_getc(void) { int c; if(rx_len == 0) /* kein Zeichen im Ringpuffer */ return -1; c = (int)rx_b[rx_rd]; /* Zeichen von RP lesen */ --rx_len; /* Zeichenzaehler decrement */ if((++rx_rd) >= rx_bufsize) /* wenn Leseindex am Puffer- */ rx_rd = 0; /* ende ist, dann rx_rd = 0 */ if(rx_len <= rx_low) { rts = 1; outp(portbase|0xfc,inp(portbase|0xfc)|0x02); /* RTS = 1 */ } return(c); } /****************************** com_putc() **********************************/ /* UEBERGABEPARAMETER: */ /* char c : auszugebendes Zeichen */ /* */ /* RETURNWERT: (int) */ /* -1 wenn das Senderegister nicht leer ist, oder CTS = 0 */ /* 0 Zeichen wurde erfolgreich in des Senderegister geschrieben */ /* */ /* KURZBESCHREIBUNG: */ /* Die com_putc() Funktion schreibt den Wert "c" in das Senderegister */ /* des 8250, wenn CTS = 1 und das Senderegister leer ist. Kann nicht */ /* in das Senderegister geschrieben werden, so wird als Returnwert -1 */ /* zurueckgegeben. . */ /****************************************************************************/ int com_putc(char c) { if(((inp(portbase|0xfd)&0x20) == 0) || ((inp(portbase|0xfe)&0x10) == 0)) return(-1); /* Transfer durch Handshake gestopt */ else outp(portbase|0xf8,c); /* ins Senderegister schreiben */ return(0); } void rts_on(void) { outp(portbase|0xfc,inp(portbase|0xfc)|0x02); /* RTS = 1 */ } void rts_off(void) { outp(portbase|0xfc,inp(portbase|0xfc)&0xfd); /* RTS = 0 */ } /****************************** d_i() ***************************************/ /* UEBERGABEPARAMETER: */ /* keine */ /* */ /* RETURNWERT: (int) */ /* 1 wenn das Interrupt-Enableflag gesetzt war */ /* */ /* KURZBESCHREIBUNG: */ /* Die d_i() Funktion setzt das Interrupt-Enableflag auf 0, sodasz alle */ /* Interrupts gesperrt sind. Wird als Rueckgabewert 1 gegeben, war das */ /* IF vor aufrufen dieser Funktion auf 1 gesetzt. */ /****************************************************************************/ int d_i(void) { _asm pushf /* Flagregister in AX laden */ _asm pop ax _asm cli /* sperren der Interrupts */ _asm and ah,02h /* prufen ob IF == 1 */ _asm jnz dd1 return(0); /* INTs waren gesperrt */ dd1: return(1); /* INTs waren freigegeben */ } /****************************** e_i() ***************************************/ /* UEBERGABEPARAMETER: */ /* keine */ /* */ /* RETURNWERT: (int) */ /* keiner */ /* */ /* KURZBESCHREIBUNG: */ /* Die e_i() Funktion setzt das Interrupt-Enableflag auf 1. Damit */ /* werden auftretende Interrupts wieder weitergeleitet. */ /****************************************************************************/ void e_i(void) { _asm sti /* freigabe der Interrupts */ } //Ende com.c