Вы находитесь на странице: 1из 15

PBX (Private Branch Exchange)

Introduction
In this project, we demonstrate the 4 line telephone systems with full signaling and switching
functions similar to those of the central office systems. Dial tone, busy tone, and ring tone are
provided during call progress. Ringing is generated at the receiving end of the phone being
called. Switching employs integrated circuit (IC) matrix switches on four buses. Thus, this
system is expandable to 8 lines (4 pairs) if more hardware is added. This system is switching on
the Dual Tone Multi Frequency (DTMF) dialing signal and does not work with pulse dialing
signal founded in some older phones.

Motivation for doing this project


We were looking for a project, which offers a balance between software and
hardware. Telephone switching came to our mind after we first considered X-Y
plotter. The latter, however, is rather involved in mechanical hardware, neither of us
has really had experience on. So, we opted for telephone switching where the
hardware involved is electronics in nature.

High level design


The telephone systems we built consist of the phone line interface circuits and the
MCU on the STK2000 development board.
Each phone line interface circuit has the following hardware.
• Ringer
• Hook switch relay
• Tone frequency generator
• DTMF receiver
• IC switch
The four phones share a common ringer; for all the other components, each phone
has its own individual. This is primarily due to the wattage rating of the ICs, we use.
The MCU on the STK2000 is the central brain of the systems, whose embedded
software provides the control functions to each of the phone line interface circuits
connected to it. PORT-A is used as the address bus, which, via decoding logic,
provides the enabling signal to appropriate functional units. PORT-C is used as the
data bus that read and/or write data to those units. PORT-D is reserved for UART.
Initially, it is used for debugging during systems start-up. It can be modified to
provide the central monitoring function for the entire systems.
All communication to the functional units via the PORT is asynchronous and level
enable.
Program design
The embedded program in the MCU that provides the control functions cycle
through the state machine shown. (Receiver, Sender#1, and Sender#2)
Timer 0 is used to provide a time base for polling each phone. It is set such that
each phone gets serviced every 40 ms. Note that this is more than adequate for
phone state update as a human typically press a dial button for more than 100 ms
before releasing it.
The busy tone and ring tone cadence can be change at #define at the beginning
portion of the program.
The number assigned to each phone can be increased if we expand the states after
CALLEROFFHOOK to cycle through a number registration state machines before
moving on to CHECKRECEIVER.
The switching scheme is such that the sender acts as a master to the bus to which it
is assigned. When a receiver is available, the program switches the sender on its
bus and forces the switch on the receiving end to switch on the same bus.
We use a scheme, which the receiver is the full slave of the sender. The receiver
state after RINGING is completely determined by the sender. The receiver is able to
return to IDLE after RINGING and RECTALKING (receiver talking) only when the
sender has returned to IDLE. This is done to reduce the overall states and signaling
and, hence, simplify the programming and the required hardware.

Hardware Design
The main circuit for this project is “Phone Line Circuit”. The Phone Line Circuit(s) are
connected to Micro Controller, Decoder, Ring Generator and Telephone. Micro Controller sends
or receives data via Share Data Bus by PORT-C and sends address to the decoder by PORT-A.
The decoder receives the address, decodes the address and sends the control signal (Control
Enable and Control Latch) to each Phone Line Circuit as shown in overall system diagram. The
Phone Line Circuit(s) communicate with MCU by sending or receiving data via Shared Data
Bus. MCU uses time sharing protocol to control each Phone Line Circuit by sending the address
of the Phone Line Circuit to the decoder and sending control data to Phone Line Circuit via Data
Bus.
Each Phone Line Circuit is connected to one telephone line. In this project, there are 4 Shared
Audio Bus so we can expand the switching up to 8 lines.
The Phone Line Circuit supplies DC voltage to telephone. It receives signal from telephone,
check the number by DTMF receiver and send the number to MCU when requested. Tri-State
buffers are used to multiplex data from DTMF receiver and Off-hook detection relay of each
Phone Line Circuit to Shared Data Bus. Tri-State buffer passes through the data when it receives
Control Enable signal from Decoder. Because we use time sharing method the control signals
sent from MCU to each Phone Line Circuit will be latched when the Phone Line Circuit receives
Control Latch signal from Decoder. There are 3 sets of control signals from MCU to the Phone
Line Circuit: 1. Tone Selection, select tone presented to telephone when off-hook (Dial Tone,
Busy Tone, and Ring Tone), 2. Audio Switch Control, control audio switch to connected phone
line together for speaking, and 3. Ring Control, control relay switch ring signal to telephone line.
The Audio Bus is used to link each phone line together when there is calling. Coil and capacitors
are used to separate analog signal from DC Supply voltage. There is one off-hook detection 2-
contact relay in each Phone Line Circuit. When telephone off hook the relay will close and pull
the off-hook detection output down to GND and switch the audio channel from ringing mode to
audio mode.
Block diagram of the Phone Line Circuit can be shown in two sections, Digital/Control Section
and Analog/Audio Section as shown in next diagrams. The circuit detail can be found in
Appendix A) Schematics
Phone Line Circuit

Analog / Audio Section

Results of the design


This project can be used as telephone switching up to 8 lines. There is some noise in
line because we did not have good filter in our circuit.

Next time
If we have more time, we will add some feature of this project. Current design can
use only internal phone line. We can modify the Phone Line Circuit to support
external telephone line calling. We want our PBX has ability to connect to external
telephone line.

#include <90s8515.h>
#include <stdio.h> //for debugging using printf, etc
#include <delay.h>

#define TESTPHONE 1

#define t1 10

#define MAXPHONENO 4

#define NULLADDRESS 0x0f


#define NULLLATCH 0x07

#define DIALTONEPATTERN 0x04


#define ACTIVATEDIALTONE 0x00
#define DEACTIVATEDIALTONE 0x07

#define BUSYTONEPATTERN 0x06


#define ACTIVATEBUSYTONE 0x02
#define DEACTIVATEBUSYTONE 0x07

#define RINGTONEPATTERN 0x05


#define ACTIVATERINGTONE 0x01
#define DEACTIVATERINGTONE 0x07

#define DTMFnomsk 0x0f

#define BUSYTONEON 7 // 500/(t1*MAXPHONENO)


#define BUSYTONEOFF 7// 500/(t1*MAXPHONENO)

#define RINGTONEON 25// 2000/(t1*MAXPHONENO)


#define RINGTONEOFF 50 // 2000/(t1*MAXPHONENO)

#define IDLE 1
#define CALLEROFFHOOK 2
#define WAITBUTTONRELEASE1 3
#define WAITBUTTONRELEASE2 4
#define BUSYTONEGENON 5
#define BUSYTONEGENOFF 6
#define CHECKRECEIVER 7
#define RINGTONEGENON 8
#define RINGTONEGENOFF 9
#define SENDTALKING 10
#define RINGING 11
#define RECTALKING 12

void task1(void); //start a new conversion


void initialize(void); //all the usual mcu stuff
void checkhookswreg(void);
void checkDTMFreg(void);
void enabledialtone(void);
void disabledialtone(void);
void enablebusytone(void);
void disablebusytone(void);
void enableringtone(void);
void disableringtone(void);
void enableringer(void);
void disableringer(void);
void enableswitching(void);
void disableswitching(void);

unsigned char reload, time1, phoneindex, temp1, hookswreg, ringerswreg,


DTMFvalid, temp2;
unsigned char phoneoffhook, recphoneoffhook, phonering;
unsigned char stateofphone[MAXPHONENO],tmp1,tmp2,tmp3;
unsigned char phonemsk[MAXPHONENO] = {0x01, 0x02, 0x04, 0x08};
unsigned char addrofphlatch[MAXPHONENO] = {0x1f, 0x2f, 0x3f, 0x4f};
unsigned char addrofDTMF[MAXPHONENO] = {0x5f, 0x6f, 0x7f, 0x8f};
unsigned char DTMFreg[MAXPHONENO];
unsigned char DTMFno[MAXPHONENO];
unsigned char switchtable[MAXPHONENO] = {0x0f, 0x17, 0x27, 0x47};
int oninterval[MAXPHONENO];
int offinterval[MAXPHONENO];

//timer 0 overflow ISR


interrupt [TIM0_OVF] void timer0_overflow(void)
{
//reload to force 1 mSec overflow
TCNT0=reload;

if (time1>0) --time1;
}

void main(void)
{
initialize();

//main task scheduler loop -- never exits!


while(1) {
if (time1==0) {
task1();
phoneindex++;
if (phoneindex == MAXPHONENO) phoneindex = 0;
}
}
}

void task1(void)
{

time1 = t1;
if (tmp1 != stateofphone[0] || tmp2 != stateofphone[1] || tmp3 !=
stateofphone[2]) {
printf("P1=%d P2=%d P3=%d
\n\r",stateofphone[0],stateofphone[1],stateofphone[2]);
tmp1= stateofphone[0];
tmp2= stateofphone[1];
tmp3= stateofphone[2];
}
if (stateofphone[phoneindex] == IDLE) {

// // if (phoneindex == TESTPHONE) printf("IDLE\n\r");

checkhookswreg();
phoneoffhook = hookswreg & phonemsk[phoneindex];
phonering = ringerswreg & phonemsk[phoneindex];
if ((phoneoffhook != 0) && (phonering != 0))
stateofphone[phoneindex] = RECTALKING;
else if ((phoneoffhook != 0) && (phonering == 0)) {
enabledialtone();
stateofphone[phoneindex] = CALLEROFFHOOK;
}
else if ((phoneoffhook == 0) && (phonering != 0))
stateofphone[phoneindex] = RINGING;
}
else if (stateofphone[phoneindex] == CALLEROFFHOOK) {

// // if (phoneindex == TESTPHONE) printf("CALLEROFFHOOK\n\r");

checkhookswreg();
phoneoffhook = hookswreg & phonemsk[phoneindex];
if (phoneoffhook == 0) {
disabledialtone();
stateofphone[phoneindex] = IDLE;
}
else {
checkDTMFreg();
if (DTMFvalid == 1) {
DTMFno[phoneindex] = DTMFreg[phoneindex] &
DTMFnomsk;

// if (phoneindex == TESTPHONE) printf("Number


= %d\n\r", DTMFno[phoneindex]);

if ((DTMFno[phoneindex] >=1) &&


(DTMFno[phoneindex] <= MAXPHONENO)) {
disabledialtone();
stateofphone[phoneindex] =
WAITBUTTONRELEASE1;
}
else {
disabledialtone();
stateofphone[phoneindex] =
WAITBUTTONRELEASE2;
}
}
}
}
else if (stateofphone[phoneindex] == WAITBUTTONRELEASE1) {
// if (phoneindex == TESTPHONE)
printf("WAITBUTTONRELEASE1\n\r");

checkhookswreg();
phoneoffhook = hookswreg & phonemsk[phoneindex];
if (phoneoffhook == 0)
stateofphone[phoneindex] = IDLE;
else {
checkDTMFreg();
if (DTMFvalid == 0) stateofphone[phoneindex] = CHECKRECEIVER;
}
}
else if (stateofphone[phoneindex] == WAITBUTTONRELEASE2) {

// if (phoneindex == TESTPHONE)
printf("WAITBUTTONRELEASE2\n\r");

checkhookswreg();
phoneoffhook = hookswreg & phonemsk[phoneindex];
if (phoneoffhook == 0)
stateofphone[phoneindex] = IDLE;
else {
checkDTMFreg();
if (DTMFvalid == 0) {
oninterval[phoneindex] = BUSYTONEON;
enablebusytone();
stateofphone[phoneindex] = BUSYTONEGENON;
}
}
}
else if (stateofphone[phoneindex] == BUSYTONEGENON) {

// if (phoneindex == TESTPHONE) printf("BUSYTONEGENON\n\r");

checkhookswreg();
phoneoffhook = hookswreg & phonemsk[phoneindex];
if (phoneoffhook == 0) {
disablebusytone();
stateofphone[phoneindex] = IDLE;
}
else {
oninterval[phoneindex]--;
if (oninterval[phoneindex] == 0) {
offinterval[phoneindex] = BUSYTONEOFF;
disablebusytone();
stateofphone[phoneindex] = BUSYTONEGENOFF;
}
}
}
else if (stateofphone[phoneindex] == BUSYTONEGENOFF) {

// if (phoneindex == TESTPHONE) printf("BUSYTONEGENOFF\n\r");

checkhookswreg();
phoneoffhook = hookswreg & phonemsk[phoneindex];
if (phoneoffhook == 0)
stateofphone[phoneindex] = IDLE;
else {
offinterval[phoneindex]--;
if (offinterval[phoneindex] == 0) {
oninterval[phoneindex] = BUSYTONEON;
enablebusytone();
stateofphone[phoneindex] = BUSYTONEGENON;
}
}
}
else if (stateofphone[phoneindex] == CHECKRECEIVER) {

// if (phoneindex == TESTPHONE) printf("CHECKRECEIVER\n\r");

checkhookswreg();
phoneoffhook = hookswreg & phonemsk[phoneindex];
if (phoneoffhook == 0)
stateofphone[phoneindex] = IDLE;
else
if (stateofphone[DTMFno[phoneindex] - 1] != IDLE) {
oninterval[phoneindex] = BUSYTONEON;
enablebusytone();
stateofphone[phoneindex] = BUSYTONEGENON;
}
else {
oninterval[phoneindex] = RINGTONEON;
ringerswreg = ringerswreg |
phonemsk[DTMFno[phoneindex] - 1];

enableringer();
enableringtone();
stateofphone[phoneindex] = RINGTONEGENON;
}
}
else if (stateofphone[phoneindex] == RINGTONEGENON) {

// if (phoneindex == TESTPHONE) printf("RINGTONEGENON\n\r");

checkhookswreg();
phoneoffhook = hookswreg & phonemsk[phoneindex];
recphoneoffhook = hookswreg & phonemsk[DTMFno[phoneindex] -
1];
if (phoneoffhook == 0) {
disableringer();
disableringtone();
ringerswreg = ringerswreg &
~phonemsk[DTMFno[phoneindex] - 1];
stateofphone[phoneindex] = IDLE;
stateofphone[DTMFno[phoneindex] - 1] = IDLE;
}
else {
if (recphoneoffhook == 0) {
oninterval[phoneindex]--;
if (oninterval[phoneindex] == 0) {
offinterval[phoneindex] = RINGTONEOFF;
disableringer();
disableringtone();
stateofphone[phoneindex] =
RINGTONEGENOFF;
}
}
else {
disableringer();
disableringtone();
enableswitching();
ringerswreg = ringerswreg &
~phonemsk[DTMFno[phoneindex] - 1];

stateofphone[phoneindex] = SENDTALKING;
}
}
}
else if (stateofphone[phoneindex] == RINGTONEGENOFF) {

// if (phoneindex == TESTPHONE) printf("RINGTONEGENOFF\n\r");

checkhookswreg();
phoneoffhook = hookswreg & phonemsk[phoneindex];
recphoneoffhook = hookswreg & phonemsk[DTMFno[phoneindex] -
1];
if (phoneoffhook == 0) {
stateofphone[phoneindex] = IDLE;
// if (phoneindex == TESTPHONE) printf("call to %d
(ringoff)\n\r",DTMFno[phoneindex] - 1);
stateofphone[DTMFno[phoneindex] - 1] = IDLE;
ringerswreg = ringerswreg &
~phonemsk[DTMFno[phoneindex] - 1];

}
else {
if (recphoneoffhook == 0) {
offinterval[phoneindex]--;
if (offinterval[phoneindex] == 0) {
oninterval[phoneindex] = RINGTONEON;
enableringer();
enableringtone();
stateofphone[phoneindex] =
RINGTONEGENON;
}
}
else {
enableswitching();
ringerswreg = ringerswreg &
~phonemsk[DTMFno[phoneindex] - 1];

stateofphone[phoneindex] = SENDTALKING;
}
}
}
else if (stateofphone[phoneindex] == SENDTALKING) {

// if (phoneindex == TESTPHONE) printf("SENDTALKING\n\r");

checkhookswreg();
phoneoffhook = hookswreg & phonemsk[phoneindex];
if (phoneoffhook == 0) {
disableswitching();
stateofphone[phoneindex] = IDLE;
stateofphone[DTMFno[phoneindex] - 1] = IDLE;
}
}
else if (stateofphone[phoneindex] == RINGING) {

// if (phoneindex == TESTPHONE) printf("RINGING\n\r");

checkhookswreg();
phoneoffhook = hookswreg & phonemsk[phoneindex];
if (phoneoffhook != 0)
stateofphone[phoneindex] = RECTALKING;
}
else if (stateofphone[phoneindex] == RECTALKING) {

// if (phoneindex == TESTPHONE) printf("RECTALKING\n\r");

}
}

void checkhookswreg(void)
{
DDRA = 0xf0;
PORTA = 0x0f;
delay_us(10);
temp2 = PINA;
hookswreg = ~temp2;
// if (phoneindex == TESTPHONE) printf("hoowswreg = %d", hookswreg);
}

void enabledialtone(void)
{
DDRC = 0xff;
PORTC = DIALTONEPATTERN;
delay_us(5);
PORTA = addrofphlatch[phoneindex];
delay_us(5);
PORTC = ACTIVATEDIALTONE;
delay_us(5);
PORTA = NULLADDRESS;
}

void disabledialtone(void)
{
DDRC = 0xff;
PORTC = DEACTIVATEDIALTONE;
delay_us(5);
PORTA = addrofphlatch[phoneindex];
delay_us(5);
PORTA = NULLADDRESS;
}

void enablebusytone(void)
{
DDRC = 0xff;
PORTC = BUSYTONEPATTERN;
delay_us(5);
PORTA = addrofphlatch[phoneindex];
delay_us(5);
PORTC = ACTIVATEBUSYTONE;
delay_us(5);
PORTA = NULLADDRESS;
}

void disablebusytone(void)
{
DDRC = 0xff;
PORTC = DEACTIVATEBUSYTONE;
delay_us(5);
PORTA = addrofphlatch[phoneindex];
delay_us(5);
PORTA = NULLADDRESS;
}

void enableringtone(void)
{
DDRC = 0xff;
PORTC = RINGTONEPATTERN;
delay_us(5);
PORTA = addrofphlatch[phoneindex];
delay_us(5);
PORTC = ACTIVATERINGTONE;
delay_us(5);
PORTA = NULLADDRESS;
}

void disableringtone(void)
{
DDRC = 0xff;
PORTC = DEACTIVATERINGTONE;
delay_us(5);
PORTA = addrofphlatch[phoneindex];
delay_us(5);
PORTA = NULLADDRESS;

void enableringer(void)
{
PORTB = ~ringerswreg;
}

void disableringer(void)
{
temp1 = ringerswreg & ~phonemsk[DTMFno[phoneindex] - 1];
PORTB = ~temp1;
}

void enableswitching(void)
{
DDRC = 0xff;
PORTC = switchtable[phoneindex];
delay_us(5);
PORTA = addrofphlatch[phoneindex];
delay_us(5);
PORTA = addrofphlatch[DTMFno[phoneindex] - 1];
delay_us(5);
PORTA = NULLADDRESS;
}

void disableswitching(void)
{
DDRC = 0xff;
PORTC = NULLLATCH;
delay_us(5);
PORTA = addrofphlatch[phoneindex];
delay_us(5);
PORTA = addrofphlatch[DTMFno[phoneindex] - 1];
delay_us(5);
PORTA = NULLADDRESS;
}

void checkDTMFreg(void)
{
DDRC = 0x00;
PORTC = 0x00;
PORTA = addrofDTMF[phoneindex];
delay_us(10);
if (PINC.4 == 1) {
DTMFvalid = 1;
DTMFreg[phoneindex] = PINC;
}
else
DTMFvalid = 0;
delay_us(5);
PORTA = NULLADDRESS;
}

void initialize(void)
{
//serial port set up
UCR = 0x10 + 0x08;
UBRR = 25;

DDRA = 0xf0;
PORTA = 0x0f;

//set up timer 0
reload=256-62; //value for 1 Msec
TCNT0=reload; //preload timer 1 so that is interrupts after 1 mSec.
TCCR0=3; //prescalar to 64
TIMSK=2; //turn on timer 0 overflow ISR

//init the task timer


time1=t1;

hookswreg = 0x00;
ringerswreg = 0x00;
for (phoneindex = 0; phoneindex < MAXPHONENO; phoneindex++) {
stateofphone[phoneindex] = IDLE;
DDRC = 0xff;
PORTC = NULLLATCH;
delay_us(5);
PORTA = addrofphlatch[phoneindex];
delay_us(5);
PORTA = NULLADDRESS;
}

//initialize ringer
DDRB = 0xff;
PORTB = 0xff;

phoneindex = 0;
DTMFvalid = 0;

//crank up the ISRs


#asm
sei
#endasm
}