QRPp WSPR – QRSS Software
QRPp WSPR – WSPR Software


From the very beginning I had in the back of my mind the desire to get the QRPp transmitter running WSPR. I had found several references via Google that different folks had implemented WSPR on a PIC but hadn't been successful in finding current email addresses to ask for details!

Fortunately, I found a reference that Gene W3PM had posted on the WSPRnet.org site AND a current email address for Gene. Gene kindly shared the information he'd had from Johan SM6LKM who had come up with the original design.

WSPR uses a 4 level FSK signal with each level separated by 1.465 Hz – so you need to be able to frequency shift the oscillator by:

  • Symbol 0     0 Hz
  • Symbol 1    1.465 Hz
  • Symbol 2    2.930 Hz
  • Symbol 3    4.395 Hz

These are rounded to 3 decimal places!

Adding WSPR support to the QRPp transmitter requires using a digitally controlled analog multiplexor like the 74HC4051 or 74HC4052. These parts allow a digital address to control which analog input is fed to a single multiplexed output. The analog input voltage is controlled by a 15 turn trim-pot which is set to a voltage level which shifts the oscillator frequency via the varicap diode on the oscillator.

The PIC controls the digital address lines on the multiplexor using two output port pins – in my case, RC4 and RC5.

Here's the schematic for the multiplexor (click on the schematic for a full size PDF):

Vcc for this circuit is 5v and is derived from the three terminal regulator that provides the 5v supply for the PIC controller. Its stability is adequate to provide a regulated supply to control the WSPR FSK via the varicap and the trim-pots.

Adjusting the frequency shift

Getting correct frequency shift for each symbol requires patience but is straight forward. You could choose to omit the trim-pot for symbol 0 or simply crank it down to 0 V.

I used a combination of Spectrum Lab and Argo to adjust the other three symbol levels. Measuring small frequency shifts requires either a very accurate frequency counter (mine wasn't even close in terms of accuracy at 10 MHz) or a stable receiver and DSP software.

I configured Spectrum Lab to use an audio sample rate of 48,000 samples/sec together with a FFT input size of 262,144. This requires just over 5 seconds to collect the audio samples to run the FFT and results in the width of 1 FFT bin at 0.183 Hz.

I also ran Argo set to display 30 second dots to get a small enough frequency resolution. Its easiest to center the display on the right frequency by starting with a shorter dot period and re-centering the signal in the display window – then increase the dot period.

I watched the Argo display while adjusting each trimpot to get the shift "close" – then I used the peak detector in Spectrum Lab to display the signal frequency – shifting between symbol 0 and the required symbol by controlling the PIC IO port lines to select the symbol being adjusted.

Some patience is required because the residual drift of the oscillator is something like ± 0.25 Hz over a 2 minute period once the oven has been running for about 15 minutes. So, you have to watch the peak detector readout while adjusting the trimpot and either mentally figuring out the required value for the shift or using a calculator. I used the calculator method.

It probably took about 10 minutes to get all four symbols on the right frequency shift as close as I could tell using this method.

It must be close enough because I've had WSPR spots at SNR levels down to -32 dB so the analog approach to generating WSPR works fine! I've had the transmitter running for almost 2 months now using this method of generating WSPR and stability has been fine.

Oscillator refinement

Gene and Johan both used ADS9851 DDS chip as the control oscillator to generate the frequencies under program control of the PIC. You can pre-calculate the control word for the frequency of each symbol and then load into the DDS as required. This is the approach I'm taking for the next generation QRPp transmitter but the oscillator approach works fine for a single band.

Generating WSPR symbols

A WSPR message is encoded into 162 symbols – this includes forward error correction and timing information. There are 4 different symbols – each one corresponds to a specific FSK level as described above.

The DOS command line version of WSPR can be used to generate the symbols for a specific WSPR message. You can download the command line version at:


Full instructions to use the command line version are available in the instruction file at:


Here's an example of how to generate the symbols for the message "N6TTO CM87 15" (callsign, Maidenhead grid locator and power level in dBm):

    wspr Tx 0 0.0015 0 N6TTO CM87 15 11

This will generate a list of symbols and the associated frequencies for each symbol relative to an audio frequency of 1500 Hz (the 0.0015 in the third argument). You will get an output that looks like this:

1 3 1502.197
2 1 1499.268
3 2 1500.732
4 0 1497.803

The first number is simply a count of the number of symbols (1 to 162), the second number is the symbol and the third is the audio frequency that would be generated via WSPR to drive a sound card. We're just interested in the symbol number.

I saved the output from WSPR and loaded it into Excel. With Excel, I packed the symbols into 8 bit bytes which I then pasted into the source file with the C program for the PIC.


The rest of the logic to generate the WSPR signal is all handled in software – I'll describe the C version of the WSPR software in my next post.




I spent some time deciphering the WSPR encoding technique, and wrote a basic Python implementation that can generate the code sequence for a given callsign/grid/power level. You can fetch the code from:


Mark - thanks for this and also reminds me of something I meant to add...

With the command line version of WSPR, its possible to generate an illegal message inadvertently. It seems that WSPR only accepts certain power levels that are in particular steps - for example 10, 17, 20, 23 dbm etc.

At one point, I had settled on a power output of 12 dbm and generated a message with that power level through the command line interface.

It decoded with the correct call sign but as a BadMsg under WSPR.

Since then, I've stuck with the power levels that you can select through the Options setting with the Windows version of WSPR and had no problems!


Yes, if my memory is correct, the only valid power levels are those ending with 0, 3, or 7. The intermediate values are "co-opted" for QSO mode messages of various kinds. My "genwspr" program doesn't know about those at all, nor does it probably do any error checking to make sure you don't do those messages. Caveat emptor.

The comments to this entry are closed.