Design Idea
Microcontroller emulates numerically controlled oscillator
Edited by Bill Travis
Tom Napier, North Wales, PA -- EDN, 2/21/2002
Microcontrollers commonly add intelligence or digital functions to products, but they can also provide a variety of analog signals. An 18-pin PIC 16C54 microcontroller, combined with an inexpensive, 8-bit DAC and a simple lowpass filter, can generate sine waves from dc to approximately 50 kHz with a tuning resolution of 24 bits. The accuracy and stability of the output is as good as that of the crystal driving the microcontroller. You can connect a binary data signal to one or more PIC ports to apply FSK (frequency-shift-keying), BPSK (binary-phase-shift-keying), or QPSK (quadrature-phase-shift-keying) modulation to the output. Figure 1 shows the emulation scheme, and Listing 1 controls the operation of the microcontroller. The 16C54's firmware emulates a 24-bit numerically controlled oscillator. A fixed-length loop continuously adds the contents of one set of registers (the frequency control) to another set (the phase accumulator). The phase accumulator increments at a rate proportional to the desired output frequency and wraps around once per output cycle.
With a 24-bit accumulator, the output frequency is f×N/[67108864(L+2)], where f is the clock frequency, N is the tuning control number, and L is the number of instructions in the loop. (The loop period is two instruction times longer than the instruction count, L.) For example, if the PIC's clock crystal's frequency is 16.777 MHz, and the loop has 30 instructions, you can set any frequency to approximately 40 kHz in steps of 1/128 Hz. Once per loop, the highest byte of the phase accumulator selects an output sample from a 65-element look-up table, which contains one quadrant of a sine wave. To create the other three quadrants, bit 6 determines whether to read the table forward or backward, and bit 7 specifies the output sign. An exclusive-OR operation on bit 7 with a port bit generates BPSK operation. An exclusive-OR operation on both bits 6 and 7 with port bits generates QPSK modulation. The result goes to the DAC via the PIC's 8-bit output port. A 50-kHz lowpass filter then converts the DAC's output into a smooth sine wave.
You can preset the output frequency or load it serially via two pins of the PIC's 4-bit port. You obtain FSK by using an input bit to select which of two frequency-control registers to use. If the two frequencies have a large common multiple, as in minimum-shift keying, the accumulator can be shorter, leading to a higher output frequency for a given clock input. Without modulation, the firmware loop can be as short as 26 instruction times (Listing 1). You can insert nonoperation instructions to make the loop-repetition rate a convenient submultiple of the crystal frequency. For example, a 31-instruction loop and a 20-MHz crystal yield a scale factor close to 104 steps/Hz.
The code takes advantage of a quirk in the 16C54's operation: If two addresses exist on the return stack, the first copies endlessly into the second every time the routine pops the second. The initialization code puts two copies of the loop-start address into the return stack, causing all subsequent RETLW instructions to jump to the start of the loop. Indexing into the look-up table with a calculated GOTO instruction both supplies an output sample and executes a jump to restart the loop. This procedure is much faster than executing a CALL, a GOTO, a RETLW, and a further GOTO.
Is this the best Design Idea in this issue? Select at www.ednmag.com.
















