I have tried out my idea for a WSPR setup. This is an Arduino with a AD9850 DDS generating the transmit carrier, with a DSB mixer attached. The audio input comes from an iPhone app iWSPR. I had to "trim" the DDS frequency up a bit to get it to send at 7040100 (1500 kHz modulation on a 7038600 carrier).
The receive is my recently built SDR. the output goes to the iMac through an FCA202 ADC running at 48kHz. The receiver software is the excellent DSP Radio, and this pipes its audio output via Soundflower to the WSPR program.
The real thing
Now I changed the input to the mixer to come from the WSPR software running on the iMac via the FCA202. Then I switched on the "Upload Spots". The result is, amazingly, this:
Saturday, 30 August 2014
Thursday, 28 August 2014
The Softrock + Arduino SDR
So here is the final SDR hardware and the software code
The white-yellow-red wires at the top are the audio output which I am feeding to a FCA202 ADC.
On the right you can see a 6 pin connector. This is a plagiarism of M0XPD's "RF bus", but carrying different signals as you can see below.
Schematic
The Softrock Lite ll SDR is driven with the output "TUNE" (0 output of the SI5351 module). The frequency can be set from 7000kHz to 7200kHz in 20kHz steps, but pushing the button on the left side. This sets the centre frequency of the display in DSP Radio running on the iMac.
DSP Radio listening to GB100ZZ the special event station, on 40m, celebrating Marconi transmissions from Devon UK.
Code
The white-yellow-red wires at the top are the audio output which I am feeding to a FCA202 ADC.
On the right you can see a 6 pin connector. This is a plagiarism of M0XPD's "RF bus", but carrying different signals as you can see below.
Schematic
The Softrock Lite ll SDR is driven with the output "TUNE" (0 output of the SI5351 module). The frequency can be set from 7000kHz to 7200kHz in 20kHz steps, but pushing the button on the left side. This sets the centre frequency of the display in DSP Radio running on the iMac.
DSP Radio listening to GB100ZZ the special event station, on 40m, celebrating Marconi transmissions from Devon UK.
Code
// SI5351 dds with LCD display, output is x4 display frequency to drive /4 IQ generator // ------ // DDS I2C SI5351 // SCL = A5 // SDA = A4 // address 0x60 // ------ // display I2C LCD 16 * 2 // o A5 SCL // o A4 SDA // o GND // o +5 // address 0x27 // ------ // RF bus // o GND // o from DSB // o TUNE out 0 // o SDR out 1 // o to DSB out 2 // o to TX out 2 CW/QRSS or DSB/WSPR #include "Wire.h" #include "Adafruit_SI5351.h" #include "LiquidCrystal_I2C.h" // PLL frequency, IQ multiplier #define XTAL 25 #define MULT 28 #define IQ 4 // outputs #define TUNE 0 #define SDR 1 #define CWDSB 2 // button pin 8 #define BUTTON 8 // dds object Adafruit_SI5351 dds = Adafruit_SI5351(); // LCD object LiquidCrystal_I2C lcd(0x27, 16, 2); float freq = 7000; // start TUNE freq kHz float prevfreq; void setup() { pinMode(BUTTON, INPUT_PULLUP); // button input lcd.init(); lcd.backlight(); dds.begin(); dds.setupPLLInt(SI5351_PLL_A, 28); // PLLA = 25 * 28 = 700MHz ddsout(freq); prevfreq = freq; show(freq); // display current TUNE frequency } void loop() { if(digitalRead(BUTTON) == LOW) // button pressed? { while(!digitalRead(BUTTON)); // wait button release if(freq == 7200) // if top of band { freq = 7000; // go to bottom } else { freq += 20; // increment by 20kHz } } if(freq != prevfreq) // if changed update ddsout(freq); show(freq); prevfreq = freq; } void ddsout(float f) { float plla; // PLLA freq float frac; float synth; long n; long m; int div; m = 100000; plla = XTAL * MULT; // 700MHz synth = plla/(freq/1000 * IQ); // MHz, x4 for IQ gen div = (int)synth; // get integer part frac = (synth - div) * m; // get fractional part n = (long) frac; dds.setupMultisynth(TUNE, SI5351_PLL_A, div, n, m); // out TUNE = PLLA/(div+n/m) dds.enableOutputs(true); } // display freq in MHz void show(float f) { lcd.setCursor(0, 0); lcd.print("Centre Frequency"); lcd.setCursor(4, 1); lcd.print(f, 0); lcd.setCursor(9, 1); lcd.print("kHz"); }
Monday, 25 August 2014
NEW NEW NEW! A great Digital Frequency Synthesiser
I was browsing the Arduino news the other day when I came across a new product from Adafruit.
It uses a very small SI5351 which is a PLL locked to a crystal, and subsequently divided down to the output you want. It has two PLLs and three outputs, all separately programmable.
Here's the very simple connections:
What I have in mind is to squeeze a Softrock Lite ll SDR radio and one of these onto an Arduino shield to make a complete tuneable SDR. Unfortunately my build of the Softrock went wrong as I mounted the FST3253 IC up-side-down! Now I am waiting for replacement parts.
Code
It uses a very small SI5351 which is a PLL locked to a crystal, and subsequently divided down to the output you want. It has two PLLs and three outputs, all separately programmable.
Here's the very simple connections:
What I have in mind is to squeeze a Softrock Lite ll SDR radio and one of these onto an Arduino shield to make a complete tuneable SDR. Unfortunately my build of the Softrock went wrong as I mounted the FST3253 IC up-side-down! Now I am waiting for replacement parts.
Code
// SI5351 dds #include "Wire.h" #include "Adafruit_SI5351.h" // PLL frequency #define XTAL 25 #define MULT 28 // dds object Adafruit_SI5351 dds = Adafruit_SI5351(); float pll; // PLL freq float freq = 3.6; // requested output freq void setup() { Serial.begin(9600); dds.begin(); dds.setupPLLInt(SI5351_PLL_A, 28); // PLL = 25 * 28 = 700MHz Serial.println(freq); } void loop() { float frac; float synth; long n; long m; int div; m = 100000; pll = XTAL * MULT; synth = pll/freq; div = (int)synth; // get integer part frac = (synth - div) * 100000; // get fractional part n = (long) frac; Serial.print("Frequency = "); Serial.println(freq); dds.setupMultisynth(0, SI5351_PLL_A, div, n, m); // out = PLL/(div+n/m) dds.enableOutputs(true); freq = get(); // get input freq MHz } // get input as an float float get() { float in; while(Serial.available() > 0) Serial.read(); while(Serial.available() == 0) in = Serial.parseFloat(); return in; }
Friday, 22 August 2014
Response plotter
I had a quick idea yesterday. To take an AD9850, set a start and end frequencies, and a step frequency. Then drive it to step from start to end.
The output would then be fed to a tuned circuit, and the response measured by an RF probe and fed to the analog input of the Arduino.
The Analog input would be plotted against frequency to show the tuned circuit's response curve.
Here's the setup:
The control is the rotary encoder. First turn it to select the start frequency, then push the button, now select the end frequency. A further push starts the scan. Like this
The result is shown on the Monitor, like this
Code
The output would then be fed to a tuned circuit, and the response measured by an RF probe and fed to the analog input of the Arduino.
The Analog input would be plotted against frequency to show the tuned circuit's response curve.
Here's the setup:
The control is the rotary encoder. First turn it to select the start frequency, then push the button, now select the end frequency. A further push starts the scan. Like this
The result is shown on the Monitor, like this
Code
// CONNECTIONS // A5-A0 side // ------ // encoder KY-040 // o Grey 2 CK // o White 3 DT // o Blue 8 SW // o Violet +5 // o Black GND // // display I2C LCD 16 * 2 // o Green A5 SCL // o Yellow A4 SDA // o Red GND // o Orange +5 // ------ // D0-D13 side // // RF bus hardware output // o GND // o DSB out // o I to SDR // o Q to SDR // o S0 to DSB in // o S1 to TX (selectable S1 ad9850 or DSB out) // // selector output to S1: CW-S1-DSB #include "Encoder.h" #include "DDS.h" #include "Wire.h" #include "LiquidCrystal_I2C.h" // encoder pin connections and +5V & GND #define CK 2 #define DT 3 #define BUTTON 8 // pin Button // DDS pin connections #define RST 4 // Pin RST #define DATA 5 // Pin DATA #define FQ 6 // Pin FQ #define CLK 7 // Pin CLK // input connection #define IN A0 // I2C connections #define SDA A4 #define SCL A5 // commands #define SF 0 // set start freq #define EF 1 // set end freq #define SC 2 // scan start // output print scale factor #define FACTOR 2 // Encoder object Encoder enc(DT, CK); // DDS object DDS dds(CLK, FQ, DATA, RST); // LCD object LiquidCrystal_I2C lcd(0x27, 16, 2); double freq; // scan frequency double freq1 = 6500000L; // init start & end double freq2 = 7500000L; long tune = 10000L; // fix button tune step and scan delta steps long delta = 50000L; long pos = 0; // enc positions long newpos; byte act = 0; // init set freq1 void setup() { pinMode(BUTTON, INPUT_PULLUP); // button input Serial.begin(9600); // serial comms enc.write(0); // init encoder dds.init(); // init DDS dds.setFrequency(freq1); // set start freq lcd.init(); // init LCD lcd.backlight(); } void loop() { byte tag; if(digitalRead(BUTTON) == LOW) // button pressed? { while(!digitalRead(BUTTON)); // wait for button release if(act == 2) act = 0; // chose actions else act++; } switch(act) // change delta freq { case SF: // change start freq1 in 100kHz steps tag = 0; freq1 = change(freq1); break; case EF: // change end freq2 in 100kHz steps tag = 1; freq2 = change(freq2); break; case SC: // start scan tag = 2; for(freq = freq1; freq <= freq2; freq += delta) { delay(50); dds.setFrequency(freq); // output freq show(tag, freq1, freq); // display scan freq volts(freq, analogRead(IN)); // output to monitor } act = 0; break; } show(tag, freq1, freq2); } // change freq, returns new freq long change(long f) { // encoder read, updates freq newpos = enc.read(); if(newpos != pos) f += tune * (newpos - pos) / 4; // enc gives 4 pulses per click! pos = newpos; return f; } // display start & end freqs in MHz void show(byte t, double f1, double f2) { if(t == 0) // line 1 delete ">", line 0 put ">" { lcd.setCursor(0,1); lcd.print(" "); lcd.setCursor(0,0); lcd.print(">"); } if(t == 1) // line 0 delete ">", line 1 put ">" { lcd.setCursor(0,0); lcd.print(" "); lcd.setCursor(0,1); lcd.print(">"); } if(t == 0 || t == 1) // line 0 f1 or "SCAN" { lcd.setCursor(4,0); lcd.print(f1/1000000, 6); lcd.setCursor(13,0); lcd.print("MHz"); } else if(t == 2) { lcd.setCursor(4,0); lcd.print("SCAN "); } lcd.setCursor(4,1); lcd.print(f2/1000000, 6); lcd.setCursor(13,1); lcd.print("MHz"); } // output freq & A0 to monitor void volts(long f, int in) { int n; Serial.print(f); n = in/FACTOR; while(n-- > 0) { Serial.print(" "); } Serial.println("X"); }
SDR - this is what I will do
I have struggled to build an SDR for the Arduino DDS board to tune. So I have decided to get someone else's design and mount it on an shield board.
The simple, obvious choice is the Softrock Lite ll from Tony Parks. This is a basic SDR which is what I want to build anyway, but it is debugged and ready to go. So here' what I propose.
1. Crop the schematic to accept an input from the AD9850 DDS shield I have built.
2. Then plan a shield like this
I have ordered a kit from SDR-Kits as Fivedash are out of stock at the moment - coming soon they say...
Can't wait to see how it goes.
The simple, obvious choice is the Softrock Lite ll from Tony Parks. This is a basic SDR which is what I want to build anyway, but it is debugged and ready to go. So here' what I propose.
1. Crop the schematic to accept an input from the AD9850 DDS shield I have built.
2. Then plan a shield like this
I have ordered a kit from SDR-Kits as Fivedash are out of stock at the moment - coming soon they say...
Can't wait to see how it goes.
Wednesday, 6 August 2014
WSPR - whisper
WSPR is a very low power, very slow way of transmitting some key information. It is used to test propagation conditions. You have your own WSPR transmitter, and other people will receive you. The reception data is collected on a web site and you can get an immediate map of where you are being received.
I have got a WSPR system for reception going here.
I use my browser, Safari, and connect to the web SDR receiver at websdr.ewi.utwente.nl:8901. Then I pipe the output of Safari, normally connected to the system Internal Speakers, to SoundFlower (2ch).
The input to the WSPR program is taken from SoundFlower (2ch) and so it receives the sound from the SDR radio.
This is the result.
I have got a WSPR system for reception going here.
I use my browser, Safari, and connect to the web SDR receiver at websdr.ewi.utwente.nl:8901. Then I pipe the output of Safari, normally connected to the system Internal Speakers, to SoundFlower (2ch).
The input to the WSPR program is taken from SoundFlower (2ch) and so it receives the sound from the SDR radio.
This is the result.
Tuesday, 5 August 2014
Arduino breadboard proto
I searched the web for ages to try to find a simple Arduino blank proto board. So many of them have added items like a reset button, LED, area to mount an SO IC chip, etc etc.
But if you want a plain proto board you can get one...
,,. from Electan:
Now that is useful!
But if you want a plain proto board you can get one...
,,. from Electan:
Now that is useful!
Monday, 4 August 2014
LCD using I2C serial access
I have been struggling for days to try to get my LCD 1602 display, with an I2C interface board on the back, working.
To do this one needs a library called "LiquidCrystal_I2C.h" which is referenced in many places on the web. But it seems a shambles as many of the sources have modified the library code to suit a particular application and they simply don't work. I downloaded at least 5 different versions none of which worked, and my LCD just showed a line of white rectangles, nothing else.
I have now found a version of the library which works!! So if you have the same difficulty go over to the site of HobbyComponents, search for their LCD display with I2C interface, then go to the forum and there you will find a download of the library which works.
Good luck!
To do this one needs a library called "LiquidCrystal_I2C.h" which is referenced in many places on the web. But it seems a shambles as many of the sources have modified the library code to suit a particular application and they simply don't work. I downloaded at least 5 different versions none of which worked, and my LCD just showed a line of white rectangles, nothing else.
I have now found a version of the library which works!! So if you have the same difficulty go over to the site of HobbyComponents, search for their LCD display with I2C interface, then go to the forum and there you will find a download of the library which works.
Good luck!
Saturday, 2 August 2014
DDS AD9850 with encoder input and LCD display
Here's a sketch to use an AD9850 DDS with input from an encoder and output to an LCD display. This sketch will be further developed to display more parameters and to have inputs to change the scanning speed. The current one, here, increments the frequency by 10, 100, 1kHz or 10kHz per step when you press the encoder knob, not the most practical way to tune a radio.. will have to give this some thought.
// DDS AD9850, encoder input // display on LCD 16 * 2 // encoder A = 2, C (centre) = GND & B = 3 #include "DDS.h" #include "Wire.h" #include "LiquidCrystal_I2C.h" #define ENCA 2 #define ENCB 3 // pin connections #define RST 4 // Pin RST #define DATA 5 // Pin DATA #define FQ 6 // Pin FQ #define CLK 7 // Pin CLK #define BUTTON 8 // pin Button // frequency change, by df #define NC 0 #define UP 1 #define DWN 2 // I2C connections #define SDA A4 #define SCL A5 // DDS object DDS dds(CLK, FQ, DATA, RST); // LCD object LiquidCrystal_I2C lcd(0x27, 16, 2); double freq = 3600000L; // start freq Hz double df = 100; // 100Hz change in frequency per click byte chg = NC; // flag NC = no change, UP = add df, DWN = subtract df byte dsw = 0; // delta freq = 10Hz char *dtxt[4] = { " 10", "100", " 1K", "10K"}; // delta freq display values void setup() { pinMode(ENCA, INPUT_PULLUP); // encoder inputs pinMode(ENCB, INPUT_PULLUP); pinMode(BUTTON, INPUT_PULLUP); // button input attachInterrupt(0, doEnc, CHANGE); // interrupt on any change of pin 2 dds.init(); dds.setFrequency(freq); lcd.init(); lcd.backlight(); show(freq); } void loop() { int state; switch (chg) { case NC: break; case UP: freq += df; show(freq); break; case DWN: freq -= df; show(freq); break; } chg = NC; dds.setFrequency(freq); if(digitalRead(BUTTON) == LOW) // button pressed? { if(dsw == 3) dsw = 0; else dsw++; } switch(dsw) { case 0: df = 10; break; case 1: df = 100; break; case 2: df = 1000; break; case 3: df = 10000; break; } while(!digitalRead(BUTTON)); // wait for button release showd(dsw); } // display freq in MHz void show(double f) { lcd.setCursor(0, 0); lcd.print("VHF"); lcd.setCursor(4, 0); lcd.print(f/1000000, 6); lcd.setCursor(13,0); lcd.print("MHz"); } // display delta freq void showd(byte d) { lcd.setCursor(0, 1); lcd.print("STEP"); lcd.setCursor(5,1); lcd.print(dtxt[d]); } void doEnc() { if(digitalRead(ENCA) == digitalRead(ENCB)) chg = UP; else chg = DWN; }
DDS AD9850 Serial I/O
This is a simple sketch to use the AD9850 DDS with input from the keyboard (frequency in Hz) and display of the output frequency on the IDE Monitor.
// DDS AD9850, keyboard frequency input, use DDS library // set Monitor for "Newline" 9600 baud #include "DDS.h" // pin connections #define RST 4 // Pin RST #define DATA 5 // Pin DATA #define FQ 6 // Pin FQ #define CLK 7 // Pin CLK // DDS object DDS dds(CLK, FQ, DATA, RST); // start frequency double newfreq = 7100000L; // 7.1MHz void setup() { Serial.begin(9600); while(!Serial); dds.init(); dds.setFrequency(newfreq); } void loop() { double freq; freq = newfreq; Serial.print("Frequency = "); Serial.print(freq); Serial.println(" Hz"); newfreq = (double)get(); if(newfreq != freq) dds.setFrequency(newfreq); } // get input as a float float get() { float n; while(Serial.available() > 0) Serial.read(); while(Serial.available() == 0) n = Serial.parseFloat(); return n; }
Subscribe to:
Posts (Atom)