Generating DTMF by Compare-Match interrupts
Both timer 0 and timer 1 were used in this project. Timer 0 was used generate the time base for task scheduling whereas timer 1 was used for compare-match interrupts. Both compare-match A and compare-match B to generate sine waves with different frequencies. Since both interrupts use the same timer (i.e. timer 1), we cannot use "clear on match" to reset TCNT1; otherwise, the slower sine wave (lower frequency) will never be generated. To solve this problem, first, a 16-sample sine table is stored in a flash table. Sine the clock is running at 8 MHz, the value of the sine wave should be updated once timer 1 reaches (8 MHz/16)/frequency = 500000/frequency. Hence, OCR1A and OCR1B are initially set to two variables offset1 (=500000/frequency1) and offset2 (=500000/frequency2), where offset1 and offset2 will remain constant until the next digit is to be dialed. Once an interrupt, whoever it is, occurs, its OCR1X value will be updated as follows:
OCR1X = OCR1X + offsetX
By updating OCR1A and OCR1B in this way, each interrupt can be invoked periodically according to their corresponding frequencies. Therefore, two 8-bit digital sine waves with different frequencies are created and will be converted by the DACs to analog.
Since we used two microcontrollers in our projects, we wrote two C programs (edirectory.c, decode.c) and each of them runs on different MCU. edirectory.c basically implements all the functions of the e-directory. decode.c interprets and displays the result of the DTMF decoder. The descriptions of each function inside the C programs are given below.
Functions in edirectory.c
Sets up timers, flags, ports, variables, etc.
Scans the button pushed by the user. The button push is stored in a variable called butnum, ranging from 0-16, like the way we did in the lab
It is a state machine that debounces the button and constructs an entry/command.
It checks which mode the user is in currently and execute the corresponding mode function.
After the user finishes entering a name and presses 'enter', nameflag is set to 1 so that function knows that the next set of characters to be entered is the phone number. The name is stored in namearray and the size of database is increased by 1. After the user finishes entering the phone number and presses enter, the phone number will be stored in the phonearray and the function is done (doneflag is set to 1).
After the user finishes entering a name and presses enter, a search through the data base is executed. data_curr points to the matching data and the function is done with execution.
Increases/decreases a pointer called data_curr for up/down button.
Deletes the current entry by replacing it with the last entry in the database. The size of the database is decreased by one.
The DTMF generator is enabled by setting the variable en_DTMF to 1. The dialing state machine will start generating the dial tones for each phone number digits. All other functions cannot be executed until the e-directory finishes generating all dial tones of the current phone number.
It keeps checking if there the user has pushed the "enter" button which means the user finishes entering a name or phone number, or decides to dial or delete.
It updates the screen every 40 msec. It displays differently according to different mode.
It implements a state machine that generates a sequence of DTMF segments corresponding to the phone number. Each DTMT segment lasts for 50 msec and is separated by a 50 msec silence period so that the DTMF decoder can recognize two consecutive digits of the same value.
Adjusts OCR1A and OCR1B for the two compare-match interrupts that we use to generate the sine waves.
Functions in decode.c
Sets up everything
When DV (data valid) is one, it decodes and display the decoded digit on the LCD. After the phone number is decoded, the decoder will wait for 1 minute. If there is no more tones to be decoded, the LCD screen will be cleared waiting for a new phone number.