Created
April 20, 2015 21:12
-
-
Save NT7S/3acfd9e00e60b1bfd0f6 to your computer and use it in GitHub Desktop.
Si5351 Antenna Analyzer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <si5351.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <math.h> | |
#include <Wire.h> | |
#include <DFR_Key.h> | |
#include <LiquidCrystal.h> | |
#define V_SAMPLE A1 | |
#define I_SAMPLE A2 | |
#define Z0 50 | |
#define SLOPE 0.178 | |
#define INTERCEPT -76 | |
LiquidCrystal lcd( 8, 9, 4, 5, 6, 7 ); | |
Si5351 si5351; | |
DFR_Key keypad; | |
int index = 0; | |
float swr = 0.0F; | |
float ant_v, ant_i, ant_z; | |
unsigned long freq = 28500000UL; // Initialization frequency | |
unsigned int tune_step = 5; // This is in 10^tune_step Hz | |
void setup() | |
{ | |
// Start up serial | |
Serial.begin(57600); | |
// Setup the LCD | |
lcd.begin(16, 2); | |
lcd.cursor(); | |
// Setup keypad | |
keypad.setRate(10); | |
// Setup ADC | |
pinMode(V_SAMPLE, INPUT); | |
pinMode(I_SAMPLE, INPUT); | |
// Setup Si5351 | |
si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0); | |
si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_2MA); | |
si5351.set_correction(0); // Change to appropriate cal constant | |
} | |
void loop() | |
{ | |
char temp_str[17]; | |
unsigned int v_adc, i_adc, key; | |
// Tune the Si5351A | |
tune(freq); | |
// Read SWR bridge values | |
v_adc = analogRead(V_SAMPLE); | |
i_adc = analogRead(I_SAMPLE); | |
ant_v = SLOPE * v_adc + INTERCEPT; | |
ant_i = SLOPE * i_adc + INTERCEPT; | |
ant_z = (convert_dbm_milliwatts(ant_v) / convert_dbm_milliwatts(ant_i)) * Z0; | |
if(ant_z >= Z0) | |
{ | |
swr = ant_z / Z0; | |
} | |
else | |
{ | |
swr = Z0 / ant_z; | |
} | |
sprintf_seperated(temp_str, freq); | |
lcd.setCursor(0, 0); | |
lcd.print(temp_str); | |
lcd.setCursor(0, 1); | |
lcd.print("SWR: Z: "); | |
lcd.setCursor(4, 1); | |
if(swr > 10.0F/* || swr < 1.0F*/) | |
{ | |
lcd.print(">10"); | |
lcd.setCursor(11, 1); | |
lcd.print((unsigned int)ant_z); | |
} | |
else | |
{ | |
lcd.print(swr, 2); | |
lcd.setCursor(11, 1); | |
lcd.print((unsigned int)ant_z); | |
} | |
// Set the cursor under the digit to change | |
// First find the number of digits in the freq | |
unsigned int digits = 0; | |
unsigned long temp_freq = freq; | |
while(temp_freq > 0) | |
{ | |
temp_freq /= 10; | |
digits++; | |
} | |
// Next, find number of commas in displayed freq | |
unsigned int commas = 0; | |
temp_freq = freq; | |
while(temp_freq > 999) | |
{ | |
temp_freq /= 1000; | |
commas++; | |
} | |
// Then find number of commas to skip in tune step | |
unsigned int comma_skip = 0; | |
temp_freq = power_10(tune_step); | |
while(temp_freq > 999) | |
{ | |
temp_freq /= 1000; | |
comma_skip++; | |
}; | |
// Now calculate the cursor position | |
unsigned int cur_pos = 9 + commas - tune_step - comma_skip - 1; | |
lcd.setCursor(cur_pos, 0); | |
// Read buttons | |
key = keypad.getKey(); | |
// TODO: tuning limits from library | |
switch(key) | |
{ | |
case 2: // left | |
if(tune_step < digits) | |
{ | |
tune_step++; | |
} | |
break; | |
case 3: // up | |
if(freq + power_10(tune_step) < 160000000) | |
{ | |
freq += power_10(tune_step); | |
} | |
break; | |
case 4: // down | |
if((freq > power_10(tune_step)) && (freq - power_10(tune_step) > 8000)) | |
{ | |
freq -= power_10(tune_step); | |
} | |
break; | |
case 5: // right | |
if(tune_step > 0) | |
{ | |
tune_step--; | |
} | |
break; | |
} | |
// Handle serial commands | |
while (Serial.available() > 0) // see if incoming serial data: | |
{ | |
char inData = Serial.read(); // read oldest byte in serial buffer: | |
uint32_t a; | |
switch(inData) | |
{ | |
case 'F': | |
a = Serial.parseInt(); | |
//Serial.println(a); | |
freq = a; | |
tune(freq); | |
break; | |
case 'R': | |
Serial.print(freq); | |
Serial.print(","); | |
Serial.print(swr); | |
Serial.print(","); | |
Serial.println(ant_z); | |
break; | |
} | |
} | |
} | |
void tune(unsigned long tune_freq) | |
{ | |
si5351.set_freq((unsigned long long)tune_freq * 100ULL, 0, SI5351_CLK0); | |
} | |
void sprintf_seperated(char *str, unsigned long num) | |
{ | |
// We will print out the frequency as a fixed length string and pad if less than 100s of MHz | |
char temp_str[6]; | |
int zero_pad = 0; | |
// MHz | |
if(num / 1000000UL > 0) | |
{ | |
sprintf(str, "%3lu", num / 1000000UL); | |
zero_pad = 1; | |
} | |
else | |
{ | |
strcat(str, " "); | |
} | |
num %= 1000000UL; | |
// kHz | |
if(zero_pad == 1) | |
{ | |
sprintf(temp_str, ",%03lu", num / 1000UL); | |
strcat(str, temp_str); | |
} | |
else if(num / 1000UL > 0) | |
{ | |
sprintf(temp_str, ",%3lu", num / 1000UL); | |
strcat(str, temp_str); | |
zero_pad = 1; | |
} | |
else | |
{ | |
strcat(str, " "); | |
} | |
num %= 1000UL; | |
// Hz | |
if(zero_pad == 1) | |
{ | |
sprintf(temp_str, ",%03lu", num); | |
strcat(str, temp_str); | |
} | |
else | |
{ | |
sprintf(temp_str, ",%3lu", num); | |
strcat(str, temp_str); | |
} | |
strcat(str, " MHz"); | |
} | |
unsigned long power_10(unsigned long exponent) | |
{ | |
// bounds checking pls | |
if(exponent == 0) | |
{ | |
return 1; | |
} | |
else | |
{ | |
return 10 * power_10(exponent - 1); | |
} | |
} | |
float convert_dbm_milliwatts(float dbm) | |
{ | |
return pow(10, (dbm / 10)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment