-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathDDS_sweeper.ino
352 lines (312 loc) · 9.55 KB
/
DDS_sweeper.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
/***************************************************************************\
* Name : DDS_Sweeper.BAS *
* Author : Beric Dunn (K6BEZ) *
* Notice : Copyright (c) 2013 CC-BY-SA *
* : Creative Commons Attribution-ShareAlike 3.0 Unported License *
* Date : 18 Jul 2014 *
* Version : 1.1/M0CUV *
* Notes : Written using for the Arduino Micro *
* : Pins: *
* : A0 - Reverse Detector Analog in *
* : A1 - Forward Detector Analog in *
\***************************************************************************/
// Define Pins used to control AD9850 DDS
const int FQ_UD=10;
const int SDAT=11;
const int SCLK=9;
const int RESET=12;
// Pins for Fwd/Rev detectors
const int REV_ANALOG_PIN = A0;
const int FWD_ANALOG_PIN = A1;
// "ON/Scan in progress" LED on M0CUV board
const int LED=8;
// Inbuilt LED on Arduino Micro, fades waiting for input
const int INTLED=13;
int brightness = 0; // how bright the LED is
int fadeAmount = 1; // how many points to fade the LED by
int countdown = 1024; // only change brightness when this wraps round zero, so no delay needed
double Fstart_MHz = 1; // Start Frequency for sweep
double Fstop_MHz = 10; // Stop Frequency for sweep
double current_freq_MHz; // Temp variable used during sweep
long serial_input_number; // Used to build number from serial stream
int num_steps = 100; // Number of steps to use in the sweep
char incoming_char; // Character read from serial stream
int settle_delay = 10; // How long to wait in ms after setting the frequency before reading the voltages.
int oscilloscope_pin = FWD_ANALOG_PIN; // Read the forward detector, unless overridden.
// the setup routine runs once when you press reset:
void setup() {
// Configiure DDS control pins for digital output
pinMode(FQ_UD,OUTPUT);
pinMode(SCLK,OUTPUT);
pinMode(SDAT,OUTPUT);
pinMode(RESET,OUTPUT);
// Configure LED pin for digital output
pinMode(LED,OUTPUT);
pinMode(INTLED,OUTPUT);
// The unit is now "ON"
LED_on();
// Set up analog inputs, internal reference voltage
pinMode(REV_ANALOG_PIN,INPUT);
pinMode(FWD_ANALOG_PIN,INPUT);
analogReference(INTERNAL);
// initialize serial communication at 57600 baud
Serial.begin(57600);
// Reset the DDS
ResetDDS();
// Initialise the incoming serial number to zero
serial_input_number=0;
}
// the loop routine runs over and over again forever:
void loop() {
//Check for character
if(Serial.available()>0){
incoming_char = Serial.read();
switch(incoming_char){
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
serial_input_number=serial_input_number*10+(incoming_char-'0');
break;
case 'A':
//Turn frequency into FStart
Fstart_MHz = ((double)serial_input_number)/1000000;
serial_input_number=0;
break;
case 'B':
//Turn frequency into FStop
Fstop_MHz = ((double)serial_input_number)/1000000;
serial_input_number=0;
break;
case 'C':
//Turn frequency into FStart and set DDS output to single frequency
Fstart_MHz = ((double)serial_input_number)/1000000;
SetDDSFreq(Fstart_MHz*1000000);
serial_input_number=0;
break;
case 'D':
// Set the settle delay in the sweep
settle_delay = serial_input_number;
serial_input_number=0;
break;
case 'E':
// Oscilloscope reads rEverse detector
oscilloscope_pin = REV_ANALOG_PIN;
break;
case 'F':
// Oscilloscope reads Forward detector
oscilloscope_pin = FWD_ANALOG_PIN;
break;
case 'N':
// Set number of steps in the sweep
num_steps = serial_input_number;
serial_input_number=0;
break;
case 'O':
case 'o':
Perform_oscilloscope();
break;
case 'Q':
case 'q':
Serial.println("K6BEZ Antenna Analyser, modifications by M0CUV");
Serial.println("Commands: ABCDEFNOQSRV?");
break;
case 'S':
case 's':
Perform_sweep();
break;
case 'R':
case 'r':
ResetDDS();
Serial.println("Reset");
break;
case 'V':
case 'v':
Read_voltages();
break;
case '?':
// Report current configuration to PC
Serial.print("Start Freq:");
Serial.println(Fstart_MHz*1000000);
Serial.print("Stop Freq:");
Serial.println(Fstop_MHz*1000000);
Serial.print("Num Steps:");
Serial.println(num_steps);
break;
}
Serial.flush();
}
fade();
}
void fade() {
countdown --;
if (countdown == 0) {
countdown = 1024;
analogWrite(INTLED, brightness);
// change the brightness for next time through the loop:
brightness = brightness + fadeAmount;
// reverse the direction of the fading at the ends of the fade:
if (brightness == 0 || brightness == 255) {
fadeAmount = -fadeAmount ;
}
}
}
void LED_on() {
digitalWrite(LED, HIGH); // turn the LED on (HIGH is the voltage level)
}
void LED_off() {
digitalWrite(LED, LOW); // turn the LED off by making the voltage LOW
}
// An oscilloscope showed some spikes in the detector voltages at regular
// intervals, so I thought I could filter these out by taking the mode of
// several measurements. However, the oscilloscope plot of this firmware
// and the C driver showed that the mode is typically 0, and the smoothed
// values are sinusoidal. So, just average it. 80 measurements is around
// two cycles.
double analog_read_value(int pin) {
double total = 0.0;
double reading;
int i;
for (i=0; i< 80; i++) {
reading = analogRead(pin);
total += reading * reading;
}
return total / 80.0;
}
void Perform_sweep(){
double FWD=0;
double REV=0;
double VSWR;
double Fstep_MHz = (Fstop_MHz-Fstart_MHz)/num_steps;
int LED_voltage = HIGH;
int last_flip = 0;
// Set the start frequency - sometimes, this doesn't seem to work.
// Need a way of obtaining feedback that it has worked...
SetDDSFreq(Fstart_MHz*1000000);
SetDDSFreq(Fstart_MHz*1000000);
SetDDSFreq(Fstart_MHz*1000000);
SetDDSFreq(Fstart_MHz*1000000);
// Start loop
for(int i=0;i<=num_steps;i++){
//digitalWrite(LED, LED_voltage);
if(Serial.available()>0) {
Serial.println("Stop");
break;
}
// Calculate current frequency
current_freq_MHz = Fstart_MHz + i*Fstep_MHz;
// Set DDS to current frequency
SetDDSFreq(current_freq_MHz*1000000);
last_flip += settle_delay;
if (last_flip > 100) {
LED_voltage = LED_voltage == HIGH ? LOW : HIGH;
last_flip = 0;
}
// Read the forawrd and reverse voltages
REV = analog_read_value(REV_ANALOG_PIN);
FWD = analog_read_value(FWD_ANALOG_PIN);
if(REV >= FWD){
// To avoid a divide by zero or negative VSWR then set to max 999
VSWR = 999;
} else {
// Calculate VSWR
VSWR = (FWD+REV)/(FWD-REV);
}
// Send current line back to PC over serial bus
Serial.print(current_freq_MHz*1000000);
Serial.print(",0,");
Serial.print(VSWR*1000.0);
Serial.print(",");
Serial.print(FWD);
Serial.print(",");
Serial.println(REV);
}
// Send "End" to PC to indicate end of sweep
Serial.println("End");
Serial.flush();
LED_on();
ResetDDS();
}
void Perform_oscilloscope() {
const int buffer_size = 256;
int fwd_values[buffer_size];
int i;
if (Fstart_MHz != 0) {
// Set DDS to A frequency
SetDDSFreq(Fstart_MHz*1000000);
}
for (i = 0; i < buffer_size; i++) {
fwd_values[i] = (int)analogRead(oscilloscope_pin);
}
for (i = 0; i < buffer_size; i++) {
Serial.print(i);
Serial.print(" ");
Serial.println(fwd_values[i]);
}
// Send "End" to PC to indicate end of scope
Serial.println("End");
Serial.flush();
LED_on();
ResetDDS();
}
void Read_voltages() {
double FWD=0;
double REV=0;
double VSWR;
// Read the forawrd and reverse voltages
REV = analog_read_value(REV_ANALOG_PIN);
FWD = analog_read_value(FWD_ANALOG_PIN);
if (REV >= FWD) {
// To avoid a divide by zero or negative VSWR then set to max 999
VSWR = 999;
} else {
// Calculate VSWR
VSWR = (FWD+REV)/(FWD-REV);
}
Serial.print("VSWR: ");
Serial.print(int(VSWR*1000));
Serial.print(", Forward: ");
Serial.print(FWD);
Serial.print(", Reverse: ");
Serial.println(REV);
}
void ResetDDS() {
digitalWrite(RESET,HIGH);
// tRS = 5 clock cycle reset width:
// (5/125,000,000) secs in milliseconds = 4 ms
delay(4);
digitalWrite(RESET,LOW);
}
void SetDDSFreq(double Freq_Hz){
// Calculate the DDS word - from AD9850 Datasheet
int32_t f = Freq_Hz * 4294967295/125000000;
// Send one byte at a time
for (int b=0;b<4;b++,f>>=8){
send_byte(f & 0xFF);
}
// 5th byte needs to be zeros
send_byte(0);
// Strobe the Update pin to tell DDS to use values
digitalWrite(FQ_UD,HIGH);
// 7.0ns
delay(1);
digitalWrite(FQ_UD,LOW);
// Wait a little for settling
delay(settle_delay);
}
void send_byte(byte data_to_send){
// Bit bang the byte over the SPI bus
for (int i=0; i<8; i++,data_to_send>>=1){
// Set Data bit on output pin
digitalWrite(SDAT,data_to_send & 0x01);
// Strobe the clock pin
digitalWrite(SCLK,HIGH);
digitalWrite(SCLK,LOW);
}
}