Ein beliebiges Telefon wählt über das Telefonnetz einen Computer an der an das analoge Telefonnetz angeschlossen wird. Der Bildschirm des Computers wird durch einen Projekter ersetzt, der das Bild auf eine Leinwand projeziert.
Eine externe Schaltung übernimmt die Telefonnachbildung, mit derer der PC auch das Klingeln erkenn und abheben bzw. auflegen kann. Ausserdem übernimmt die Schaltung die Dekodierung der Tastentöne (DTMF-Töne) des anwählenden Telefons.
Als Schnittstelle zwischen dem PC und der externen Schaltung dient die serielle Schnittstelle.
Die Software untergliedert sich in zwei Teile. Einerseits die Telefonsteuerung, andererseits dem davon unabhängigen Hauptprogramm.
Zuerst müssen für die serielle Schnittstelle die notwendigen Einstellungen gesetzt werden. Dabei wird ein 7 Bit Wort mit einem Stopbit (entspricht 8 Bit) und eine Übertragungsrate von 30 Baud eingestellt.
Solange noch kein Anruf eingegangen ist, wird in regelmäßigen Abständen die Handshake-Leitung zum Klingelsignal abgefragt (CTS). Bei Änderungen wird deren Häufigkeit gezählt und so entschieden ob ein Anruf herein kommt. In diesem Falle wird über die Handshake-Leitung der Halteschaltung abgehoben.
Während des Anrufs wird über einen Interrupt-Handler oder pollings die serielle Schnittstelle auf neue Werte abgefragt. In der ersten Variante wird eine Callback-Routine, die das Hauptprogramm registriert hat, aufgerufen. Im zweiten Falle wird einfach vom Hauptprogramm in regelmäßigen Abständen eine Funktion zum Abfragen aufgerufen. Allerdings besteht dabei die Gefahr ein neu ankommendes Signal zu verpassen.
Eingelesen wird in drei Schritten.
In der Initialisierungs-Phase wird der Bildschirm aufgebaut und die Initialisierungsroutine der Telefonsteuerung aufgerufen. Ausserdem muss eventuell der Callback-Handler registriert werden.
Die Kontrolle über das Programm wird an die Telefonsteuerung übergeben die dann ihrerseits auf einen Anruf wartet. Sobald ein Anruf erkannt wurde wird wieder in das Hauptprogramm zurück gesprungen.
Während eines Anrufes wird eine Endlos-Schleife durchlaufen. Dabei wird die Bildschirmmarke entsprechend der von der Telefonsteuerung kommenden Daten über den Bildschirm gelenkt. Der Abruf dieser Daten wird entwerder auch in der Endlos-Schleife getätigt (polling) oder über eine Laufzeitvariable die vom Callback-Handler gesetzt wird.
teletkey.c hat die gleichen Funktionen und Konstanten wie telephon.c - damit können sie gegeneinander ausgetauscht werden. Der Zweck dieser Datei ist das Testen des Hauptprogramms ohne die externe Schaltung.
/*****************************************************************************
** **
** MATURA - PROJEKTWOCHE - TELEFONSTEUERUNG **
** **
******************************************************************************
** **
** Original Dateiname: main.c **
** Autor: Nico Edtinger **
** Erstversion: 14.05.2002 **
** Letzte Änderung: 15.05.2002 **
** Dateiversion: 0.2 **
** **
******************************************************************************
** **
** Hauptprogramm **
** **
******************************************************************************
** **
** Änderungen: **
** **
** 14.05.2002: Hinweis: statt der Telefonsteuerung wird Testweise die **
** Tastatur abgefragt **
** 15.05.2002: KEY_ Konstanten verwendet **
** Bewegbare Bildschirmmaske **
** Timeout Counter **
** Anmerkung: ausser Sch�nheitsfehlern ist das Hauptprogramm **
** nun vollst�ndig **
** **
*****************************************************************************/
#include "teletkey.c" /* test modul */
#include <stdio.h>
#include <stdlib.h>
#define WIDTH_X 80
#define WIDTH_Y 25
#define TIMEOUT_MAX 2500000
char last_key;
int key_changed = 0;
void key_callback(char key)
{
if(key_changed) {
return;
}
key_changed = 1;
last_key = key;
}
int main()
{
unsigned long timeout_counter;
unsigned int pos_x = WIDTH_X/2, pos_y = WIDTH_Y/2;
printf("main: telephone_init();\n");
telephone_init();
printf("main: telephone_register_callback_handler();\n");
telephone_register_callback_handler(key_callback);
while(1) {
timeout_counter = 0;
last_key = KEY_NULL;
printf("main: telephone_wait_for_call();\n");
telephone_wait_for_call();
printf("main: got call\n\n");
while(1) { /* main loop */
if(key_changed) {
timeout_counter = 0;
if(last_key == KEY_ESCAPE) {
printf("main: You've chosen escape\n");
break;
}
key_changed = 0;
} else {
timeout_counter++;
if(timeout_counter > TIMEOUT_MAX) {
printf("main: Timeout\n");
break;
}
}
if(!(timeout_counter % (TIMEOUT_MAX / 50))) {
gotoxy(pos_x, pos_y);
printf(" ");
switch(last_key) {
case KEY_UP:
if(pos_y > 1) {
pos_y--;
}
break;
case KEY_DOWN:
if(pos_y < (WIDTH_Y)) {
pos_y++;
}
break;
case KEY_LEFT:
if(pos_x > 1) {
pos_x--;
}
break;
case KEY_RIGHT:
if(pos_x < (WIDTH_X-1)) {
pos_x++;
}
break;
}
gotoxy(pos_x, pos_y);
textcolor(RED);
cprintf("*");
textcolor(WHITE);
}
}
telephone_deinit();
}
}
/*****************************************************************************
** **
** MATURA - PROJEKTWOCHE - TELEFONSTEUERUNG **
** **
******************************************************************************
** **
** Original Dateiname: telephone.c **
** Autor: Nico Edtinger **
** Erstversion: 14.05.2002 **
** Letzte Änderung: 17.05.2002 **
** Dateiversion: 0.4 **
** **
******************************************************************************
** **
** Modul zur Telefonsteuerung; kümmert sich um die Kommunikation und **
** Steuerung der Telefonsteuerung über die serielle Schnittstelle **
** **
******************************************************************************
** **
** Änderungen: **
** 15.05.2002: KEY_ Konstanten hinzugefügt **
** 16.05.2002: Init, Deinit, WaitForCall **
** 17.05.2002: KEY_ Konstanten an DTMF Dekoder angepasst **
** **
*****************************************************************************/
#include <dos.h>
#define KEY_UP 0x02
#define KEY_DOWN 0x50
#define KEY_LEFT 0x08
#define KEY_RIGHT 0x06
#define KEY_ESCAPE 0x0a
#define KEY_NULL 0x00
#define COM_INT_NUM 0x0c /* Interruprt-Nummer für COM1 */
#define COM_PORT_READ 0x3f8 /* Rw Daten aus serieller Leitung */
#define COM_PORT_DIV_LOW 0x3f8 /* RW Divisor Latch Lowbyte */
#define COM_PORT_DIV_HIGH 0x3f9 /* RW Divisor Latch Highbyte */
#define COM_PORT_INT_ENABLE 0x3f9 /* RW Interrupt Enable Register */
#define COM_PORT_LINE_CTRL 0x3fb /* RW Line Control */
#define COM_PORT_MODEM_WRITE 0x3fc /* RW Modem Control Register (Handshake)*/
#define COM_PORT_MODEM_READ 0x3fe /* R Modem Status Register (Handshake) */
#define COM_DIVISOR_LOW 0x0e /* ~30 Baud */
#define COM_DIVISOR_HIGH 0x74
#define COM_INT_READHSK 0x09 /* Interrupt nur bei neuem Datenwort oder Handshake */
#define COM_LINE_DIV_ACCESS 0x82 /* Modus zum setzen des Divisor Latch */
#define COM_LINE_7BIT 0x02 /* 7bit, ein Stopbit, keine Parität */
#define COM_MODEM_WRITE_RTS_MASK 0x02 /* Maske um RTS zu setzen */
#define COM_MODEM_WRITE_DTR_MASK 0x02 /* Maske um RTS zu setzen */
#define COM_MODEM_READ_CTS_MASK 0x10 /* Maske um CTS zu lesen */
/*
** Callback-Handler; wird von Interrupt-Handler aufgerufen, wenn ein neues
** Datenwort anliegt
*/
void (*key_callback_handler)(char) = NULL;
/*
** alte Interrupt-Routine
*/
void interrupt (*old_interrupt)() = NULL;
/*
** Callback-Handler für neues Datenwort registrieren. Wenn der Parameter
** NULL gesetzt wird, wird der Handler deaktiviert
*/
int telephone_register_callback_handler(void * callback_handler)
{
key_callback_handler = callback_handler;
return 1;
}
/*
** Ob Interrupt von StD des DTMF-Dekoders oder von Daten kommt
**/
int got_dataready_signal = 0;
/*
** Interrupt-Handler für die serielle Schnittstelle. Wird in der Anruf-Phase
** aufgerufen, wenn an der seriellen Schnittstelle ein neues Datenwort anliegt
** oder der DTMF Dekoder neue Daten signalisiert. Unterschieden wird über das
** got_ready_signal Flag. Bei einem neuem Datenwort wird dem Schieberegister
** der Takt gesendet. Beim nächsten Interrupt wird dieses dann eingelesen und
** mit diesem der Callback-Handler aufgerufen.
*/
interrupt void telephone_interrupt_handler()
{
char key;
int i;
unsigned char mcr;
if(!got_dataready_signal) {
got_dataready_signal = 1;
mcr = (unsigned char)inp(COM_PORT_MODEM_WRITE);
for(i = 0; i < 7; i++) {
outp(COM_PORT_MODEM_WRITE, mcr | COM_PORT_WRITE_RTS_MASK);
delay(1);
outp(COM_PORT_MODEM_WRITE, mcr);
delay(1);
}
outp(COM_PORT_MODEM_WRITE, mcr | COM_PORT_WRITE_RTS_MASK);
delay(1);
outp(COM_PORT_MODEM_WRITE, mcr);
} else {
got_dataready_signal = 0;
key = (char)inp(COM_PORT_READ);
if(key_callback_handler) {
key_callback_handler(key);
}
}
if(old_interrupt) {
old_interrupt();
}
}
/*
** Auflegen und Interrupt-Vektoren wieder zurück setzen
*/
void telephonee_deinit()
{
unsigned char mcr;
mcr = (unsigned char)inp(COM_PORT_MODEM_WRITE);
outp(COM_PORT_MODEM_WRITE, (~COM_MODE_WRITE_RTS_MASK) & mcr);
if(old_interrupt) {
setvect(COM_INT_NUM, old_interrupt);
old_interrupt = NULL;
}
/* Interrupts nur wenn abgeoben wurde */
outp(COM_PORT_INT_ENABLE, 0);
}
/*
** Initialisierung der seriellen Schnittstelle
*/
int telephone_init()
{
/* Interrupts nur wenn abgeoben wurde */
outp(COM_PORT_INT_ENABLE, 0);
/* Divisor Latch setzen */
outp(COM_PORT_LINE_CTRL, COM_LINE_DIV_ACCESS);
outp(COM_PORT_DIV_LOW, COM_DIVISOR_LOW);
outp(COM_PORT_DIV_HIGH, COM_DIVISOR_HIGH);
/* 7Bit, 1 Stopbit, keine Parität */
outp(COM_PORT_LINE_CTRL, COM_LINE_7BIT);
return atexit(telephone_deinit);
}
/*
** Warten auf einen Anruf (Phase aufgelegt)
*/
int telephone_wait_for_call()
{
unsigned char mcr;
unsigned char ring = 0;
unsigned char last_ring = 0;
unsigned char changes = 0;
mcr = (unsigned char)inp(COM_PORT_MODEM_WRITE);
/* warten */
do
{
ring = inp(COM_PORT_MODEM_READ) & COM_MODEM_CTS_MASK;
if(ring != last_ring) {
changes++;
}
}
while (changes < 50);
/* abheben */
outp(COM_PORT_MODEM_WRITE, COM_MODE_WRITE_RTS_MASK | mcr);
/* interrupt handler setzen */
if(!old_keyboard_handler) {
old_keyboard_handler = getvect(KEYBOARD_INT_NUM);
setvect(KEYBOARD_INT_NUM, telephone_interrupt_handler);
}
outp(COM_PORT_INT_ENABLE, COM_INT_READHSK);
return 1;
}
/*
** aktuellen Wert der seriellen Schnittstelle lesen. Für gepollte Abfragen
*/
char telephone_get_key()
{
char key;
key = (char)inp(COM_PORT_READ);
return key;
}
/*****************************************************************************
** **
** MATURA - PROJEKTWOCHE - TELEFONSTEUERUNG **
** **
******************************************************************************
** **
** Original Dateiname: telephone_test_key.c **
** Autor: Nico Edtinger **
** Erstversion: 14.05.2002 **
** Letzte Änderung: 15.05.2002 **
** Dateiversion: 0.2 **
** **
******************************************************************************
** **
** Testmodul - verwendet Keyboard statt Telefonsteuerung **
** **
******************************************************************************
** **
** Änderungen: **
** 15.05.2002: KEY_ Konstanten hinzugef�gt **
** **
*****************************************************************************/
#include <dos.h>
#include <stdio.h>
#include <conio.h>
#define KEY_UP 0x48
#define KEY_DOWN 0x50
#define KEY_LEFT 0x4b
#define KEY_RIGHT 0x4d
#define KEY_ESCAPE 0x01
#define KEY_NULL 0x00
#define KEYBOARD_INT_NUM 0x09
#define KEYBOARD_PORT_READ 0x060
/*
** Callback-Handler; wird von Interrupt-Handler aufgerufen, wenn ein neues
** Datenwort anliegt
*/
void (*key_callback_handler)(char) = NULL;
/*
** alte Interrupt-Routine
*/
void interrupt (*old_keyboard_handler)() = NULL;
/*
** Callback-Handler für neues Datenwort registrieren. Wenn der Parameter
** NULL gesetzt wird, wird der Handler deaktiviert
*/
int telephone_register_callback_handler(void (*callback_handler)(char))
{
key_callback_handler = callback_handler;
return 1;
}
/*
** Interrupt-Handler für die serielle Schnittstelle. Wird in der Anruf-Phase
** aufgerufen, wenn an der seriellen Schnittstelle ein neues Datenwort anliegt
** und ruft dann den Callback-Handler mit der erkannten Taste auf
*/
void interrupt telephone_interrupt_handler()
{
char key;
key = (char)inp(KEYBOARD_PORT_READ);
if(key_callback_handler) {
key_callback_handler(key);
}
if(old_keyboard_handler) {
old_keyboard_handler();
}
}
void telephone_deinit()
{
if(old_keyboard_handler) {
setvect(KEYBOARD_INT_NUM, old_keyboard_handler);
old_keyboard_handler = NULL;
}
}
/*
** Initialisierung der seriellen Schnittstelle
*/
int telephone_init()
{
printf("1, 2, 3, IN THE PLACE TO BE - WHAT MEANS INIT DONE :)\n");
return atexit(telephone_deinit);
}
/*
** Warten auf einen Anruf (Phase aufgelegt)
*/
int telephone_wait_for_call()
{
while(kbhit()) {
getch();
}
printf("WAIT FOR CALL\nHJS: WHERE IS THE ANY KEY? ;)\n\n");
getch();
if(!old_keyboard_handler) {
old_keyboard_handler = getvect(KEYBOARD_INT_NUM);
setvect(KEYBOARD_INT_NUM, telephone_interrupt_handler);
}
return 1;
}
/*
** aktuellen Wert der seriellen Schnittstelle lesen. Für gepollte Abfragen
*/
char telephone_get_key()
{
char key;
key = (char)inp(KEYBOARD_PORT_READ);
return key;
}
| Schaltungsname | Bauteil | Anmerkung |
|---|---|---|
| Schaltungsname | Bauteil | Anmerkung |
| Widerstände | ||
| R1 | VDR S10K150 | - |
| R2, R3 | 10kΩ | - |
| R4 | 150kΩ | - |
| R5, R13, R14 | 100kΩ | - |
| R6 | 39Ω | - |
| R7 | 20kΩ | - |
| R8 | 1,2kΩ | - |
| R9 | 180Ω | - |
| R10 | 39kΩ | - |
| R11, R12 | 68Ω | - |
| R15 | 270kΩ | - |
| Kondensatoren | ||
| C1, C2 | 470nF | - |
| C3 | 10nF | - |
| C4 | 10µF/63V | - |
| C5 | 150nF | - |
| C6 | 4,7µF/63V | - |
| C7, C11, C12 | 100nF | - |
| C8, C9, 10 | 1µF | bei MAX232 alle C=1µF |
| Dioden | ||
| D1, D2, D3, D4, D9, D10 | LL4148 | - |
| D5, D6, D7, D8 | 1N4001 | - |
| D11 | ZPD6V8 | - |
| Transistoren | ||
| T1, T2 | BC848 | - |
| T3 | BD139 | - |
| andere | ||
| OK1 | TLP627 | - |
| Q1 | Quarz | 3,579545 MHz |
| IC1 | Mitel MT8870D |
|
| IC2 | MAX232 | - |
| IC3 | 74F00 | - |
| IC4 | 74HC165 | - |
| JP1 | - | A/B-Leitung an 3/4 |
| SV1 | - |
|