#include <LiquidCrystal.h>
// LCD connections (RS, EN, D4, D5, D6, D7)
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);
// Analog pins for AD8307
const byte analogPinF = A0; // Forward power
const byte analogPinR = A1; // Reflected power
// AD8307 calibration parameters
const float Vreference = 5000.0; // mV
const float slopeF = 0.02618; // Slope for forward power
const float interceptF = 45.2; // Intercept for forward power
const float slopeR = 0.02618; // Slope for reflected power (adjust if different)
const float interceptR = 45.2; // Intercept for reflected power (adjust if different)
// Power measurement variables
float pow_fwd = 0; // Forward power in Watts
float pow_ref = 0; // Reflected power in Watts
float peak_power = 0; // Peak power in Watts
float swr = 1.0; // Standing Wave Ratio
unsigned long last_peak_time = 0;
const unsigned long peak_hold_time = 2000; // 2 seconds peak hold
// Bar graph variables
const byte bar_length = 16; // LCD width
float bar_level = 0; // Current bar level (0-1)
float bar_decay = 0.95; // Decay factor per loop (adjust for slower/faster decay)
const float bar_threshold = 0.01; // Minimum bar level to display
void setup() {
// Initialize LCD
lcd.begin(16, 2);
// Display initial information
lcd.setCursor(0, 0);
lcd.print("Po:");
lcd.setCursor(11, 0);
lcd.print("SW:");
// Configure ADC for better performance
analogReference(DEFAULT);
ADCSRA = (ADCSRA & 0xF8) | 0x04; // Set ADC clock divider to 16 (1MHz/16 = 62.5kHz)
}
void loop() {
// Read forward and reflected power
readPower();
// Calculate SWR
calculateSWR();
// Update peak power
updatePeak();
// Update bar graph
updateBarGraph();
// Update display
updateDisplay();
}
void readPower() {
// Read forward power
int adcValueF = analogRead(analogPinF);
float voltageF = (adcValueF / 1023.0) * Vreference;
float powerdBmF = (slopeF * voltageF) - interceptF;
pow_fwd = pow(10, (powerdBmF - 30) / 10);
// Read reflected power
int adcValueR = analogRead(analogPinR);
float voltageR = (adcValueR / 1023.0) * Vreference;
float powerdBmR = (slopeR * voltageR) - interceptR;
pow_ref = pow(10, (powerdBmR - 30) / 10);
}
void calculateSWR() {
// Calculate SWR with protection against division by zero and negative roots
if (pow_fwd > 0 && pow_ref >= 0) {
float gamma = sqrt(pow_ref / pow_fwd);
if (gamma < 1.0) {
swr = (1.0 + gamma) / (1.0 - gamma);
} else {
swr = 99.99; // Max SWR we'll display
}
} else {
swr = 1.0;
}
}
void updatePeak() {
// Update peak power if current power is higher
if (pow_fwd > peak_power) {
peak_power = pow_fwd;
last_peak_time = millis();
}
// Reset peak after hold time if no new peak detected
else if (millis() - last_peak_time > peak_hold_time) {
peak_power = pow_fwd;
}
}
void updateBarGraph() {
// Update bar level - fast attack, slow decay
float target_level = pow_fwd / 100.0; // Assuming 100W max for bar graph (adjust as needed)
if (target_level > bar_level) {
bar_level = target_level; // Fast attack
} else {
bar_level *= bar_decay; // Slow decay
}
// Clear bar if below threshold
if (bar_level < bar_threshold) {
bar_level = 0;
}
}
void updateDisplay() {
// Update peak power display
lcd.setCursor(0, 0);
lcd.print("Po:");
if (peak_power < 10) {
lcd.print(int(peak_power));
lcd.print("W ");
} else if (peak_power < 100) {
lcd.print(int(peak_power));
lcd.print("W");
} else {
lcd.print(int(peak_power));
lcd.print("W");
}
// Update SWR display
lcd.setCursor(10, 0);
lcd.print("SW:");
if (swr < 10.0) {
lcd.print(swr, 2);
} else {
lcd.print(swr, 1);
}
// Update bar graph on second line
lcd.setCursor(0, 1);
if (bar_level == 0) {
lcd.print(" "); // Clear line if no power
} else {
int bars = round(bar_level * bar_length);
bars = constrain(bars, 0, bar_length);
for (int i = 0; i < bars; i++) {
lcd.write(0xFF); // Custom character for solid block
}
for (int i = bars; i < bar_length; i++) {
lcd.write(' '); // Fill rest with spaces
}
}
}
FWD
REF
Slow
Fast
FWD
REF