Issue
156 July 2003
Stealth
Telephone Screener
Mad Dash for Flash Cash Grand Prize
Winner
TALKING
BACK
The
Screener records and plays two short announcements that
are stored as 4-bit ADPCM samples in an external EEPROM.
The quality of ADPCM is somewhat below “toll-quality”
PCM, which is the standard used by telephone companies
for digital voice transmission; however, it’s better
than many of the more complex compression algorithms
used by some answering machines and cellular phones.
The
compression algorithm was adapted from the code in a
Microchip application note after it was optimized for
10-bit uncompressed samples. [1] Two samples were packed
per byte and stored in the EEPROM.
Speech
data is saved in a 64-byte ring buffer on its way to
or from the EEPROM. This allows for the use of the EEPROM’s
internal 64-byte write buffer, which can write an entire
buffer’s worth of data in one 5-ms write cycle. With
an 8-kHz sample rate, 128 samples (64 bytes) take 16
ms to collect, so there is plenty of time to write it
out, even when allowing for I2C bus overhead.
Speech
sampling is achieved at 8 kHz via the 10-bit A/D converter.
I chose this rather than 8 bits to allow the Screener
to work with a wider range of input levels from different
phone lines. Playback uses PWM in 9-bit mode, using
four times oversampling. The result is a 32-kHz PWM
sample rate (but still an 8-kHz data rate), which eases
the analog filtering requirements over the 16-kHz rate
that would be necessary for 10-bit mode.
IN
CONTROL
A
single push-button switch allows you to select the number
of rings before answering (if pressed when the On/Off
switch is on), or to record a new pair of greeting messages
(if pressed when off).
The
battery voltage is checked each time the Screener picks
up the phone line. If it’s low, the ringing sound played
through the speaker is an on-off-on-off double ring,
instead of the usual 2 s on, 4 s off.
SOFTWARE
DETAILS
The
code was written in assembler using Microchip’s MPASM
3.20. You may download the code from the Circuit Cellar
ftp site.
Debugging
was accomplished the old-fashioned way by replacing
the MCU with a PIC16F876 and using its serial port to
output debugging data. Although it wasn’t as powerful
as using an ICD system, it proved adequate enough to
monitor the flow of software during development. The
code uses most of the flash memory, the entire RAM,
and a few EEPROM locations for configuration data.
After
first applying power, the internal peripherals are initialized
and a quick check confirms that the external EEPROM
is alive. Then, Timer2 starts, which functions as the
primary time base. The 16.384-MHz oscillator is divided
down to 32 kHz for the PWM clock and then to 8 kHz for
the audio sample interrupt routine. This is divided
further to execute the frame and debounce routines once
every 200 samples, or every 25 ms. The hardware inputs
and other status conditions are funneled through the
debounce routine and fed to the main control code via
two status bytes. This simplifies the software, because
the control flow is determined by those two bytes.
MAIN
ROUTINE
The
main routine waits for the phone to ring or for the
push button to be pressed. Then, it wakes up, executes
the appropriate function, and goes back to sleep.
When
the phone rings, it waits for a user-selectable number
of rings before answering. Next, the Screen-er picks
up the phone line, plays the first greeting to the caller,
and waits for a response (see Figure 3). If it doesn’t
hear any sounds for 5 s, it hangs up and waits for another
call.
|

(Click
here to enlarge)
|
Figure
3—The heart of the Screener is the algorithm that
decides if a machine or a human is calling. It is
deceptively simple yet quite effective. |
If
the Screener hears a voice, it waits up to 10 s for
at least 1.5 s of silence. If there isn’t a break in
the speech, which is typical of a recorded message,
then it hangs up. When a caller passes both of these
obstacles, they are assumed to be a real person, and
the Screener rings through its speaker.
The
Screener immediately hangs up for the following reasons:
if another phone on the same line is picked up; if the
phone-line voltage is interrupted, indicating that the
caller has hung up; if the push button is pressed; or
if the On/Off switch is turned off. Rather than check
for each condition throughout the main routine, a task-abort
interrupt flag (TASKINT) contains bits for each abort
condition, which are set as needed. Then, the frame
update routine checks for each condition and aborts
the main routine if any become true. Figure 3 shows
the conditions that are active while answering a call.
If
the push button is pressed and held down for several
seconds while the On/Off switch is on, you can change
the number of rings before answering by pressing the
button one time for each ring. If the switch is off
at the time, you can record a new pair of greetings
using a locally connected phone.