jueves, 12 de septiembre de 2024

Medidor de potencia y roe


 Este proyecto consiste en la construcción de un medidor de potencia y ROE digital, utilizando un Arduino Nano y una pantalla LCD 20x4 con interfaz I2C. El dispositivo está diseñado para medir con precisión la relación de ondas estacionarias (ROE) y la potencia en sistemas de radiofrecuencia, ideal para aplicaciones de radioaficionados. Incluye un pequeño circuito detector de RF para capturar las señales y calcular tanto la potencia transmitida como la ROE, ofreciendo una lectura clara y fácil de interpretar en la pantalla. La combinación de componentes sencillos y accesibles hace que este proyecto sea una solución eficaz y económica para quienes deseen monitorear el rendimiento de sus transmisores de radio.
 
 


#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 20, 4); // dirección 0x3f, 20 caracteres, 4 líneas

// definimos en qué puerto está la tensión directa y en cuál la reflejada para usarla después
char FWD = A0;
char REF = A1;
// buzzer
int BUZZER = 9;
// inicializamos valores
float SWR = 0.00;
// definimos a qué valor sonará la alarma de roe alta
float LIMITE = 2.2;

void setup() {
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Medidor Potencia SWR");
  lcd.setCursor(0, 1);
  lcd.print("transmisores");
  lcd.setCursor(0, 2);
  lcd.print("y proyectos");

  pinMode(FWD, INPUT);
  pinMode(REF, INPUT);
  pinMode(BUZZER, OUTPUT);

  beep(50);
  beep(50);
  beep(50);
  delay(3000);
}

void loop() {
  // Tensión actual de alimentación
  float TENSION = float(readVcc()) / 1000;
  // Leemos puerto
  float Vfwd = analogRead(FWD);
  float Vref = analogRead(REF);
  // Convertimos a tensiones
  float TENSION_DIRECTA = ((Vfwd * TENSION) / 1023);
  float TENSION_REFLEJADA = ((Vref * TENSION) / 1023);
  // Calculamos tensión RMS
  float RMS_DIR = TENSION_DIRECTA * 0.707 * 10; // Relación de transformación 1:10 en toroide
  float RMS_REF = TENSION_REFLEJADA * 0.707 * 10;
  // Potencias
  float POWER_DIR = (pow((RMS_DIR), 2) / 50) * 10; // Relación de transformación 1:10 en toroide
  float POWER_REF = (pow((RMS_REF), 2) / 50) * 10;
  // Despejamos las estacionarias
  float SWR = (1 + sqrt(POWER_REF / POWER_DIR)) / (1 - sqrt(POWER_REF / POWER_DIR));

  // Fin cálculos, pintamos los datos.
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("POTENCIA:");
  lcd.setCursor(12, 0);
  lcd.print(POWER_DIR);
  LCD_progress_bar(1, POWER_DIR, 0, 100);
  lcd.setCursor(0, 2);
  lcd.print("ROE:");
  lcd.setCursor(12, 2);
  lcd.print(SWR);
  if (SWR < 1.00) {
    // nada
  } else {
    LCD_progress_bar(3, SWR, 0, 10);
  }
  if (SWR > LIMITE) {
    beep(100);
    lcd.setCursor(12, 3);
    lcd.print("ALARMA");
  }
  delay(1000);  // Un segundo de retardo para refrescar pantalla
}

long readVcc() {
  // Leer referencia de 1.1V contra AVcc
  // Configurar la referencia a Vcc y la medición a la referencia interna de 1.1V
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
  ADMUX = _BV(MUX5) | _BV(MUX0);
#elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
  ADMUX = _BV(MUX3) | _BV(MUX2);
#else
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif

  delay(2); // Esperar a que se estabilice Vref
  ADCSRA |= _BV(ADSC); // Iniciar conversión
  while (bit_is_set(ADCSRA, ADSC)); // Medición en curso

  uint8_t low = ADCL; // Leer ADCL primero - luego bloquea ADCH
  uint8_t high = ADCH; // Desbloquea ambos

  long result = (high << 8) | low;

  result = 1125300L / result; // Calcular Vcc (en mV); 1125300 = 1.1*1023*1000
  return result; // Vcc en milivoltios
}

void LCD_progress_bar(int row, int var, int minVal, int maxVal) {
  int block = map(var, minVal, maxVal, 0, 20);   // El bloque representa el espacio actual del LCD
  int line = map(var, minVal, maxVal, 0, 80);    // La línea representa las líneas teóricas que se deben imprimir
  int bar = (line - (block * 5));                // La barra representa las líneas actuales que se imprimirán

  /* Caracteres de barra de progreso LCD, crea tus barras personalizadas */
  byte bar1[8] = { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10};
  byte bar2[8] = { 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18};
  byte bar3[8] = { 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C};
  byte bar4[8] = { 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E};
  byte bar5[8] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F};
  lcd.createChar(1, bar1);
  lcd.createChar(2, bar2);
  lcd.createChar(3, bar3);
  lcd.createChar(4, bar4);
  lcd.createChar(5, bar5);

  for (int x = 0; x < block; x++) {  // Imprimir todos los bloques llenos
    lcd.setCursor(x, row);
    lcd.write(5);  // Cambiado a 5 (el último bloque definido)
  }

  lcd.setCursor(block, row);  // Establecer el cursor en el bloque actual y imprimir las líneas necesarias
  if (bar != 0) lcd.write(bar);
  if (block == 0 && line == 0) lcd.write(32);  // Espacio en blanco (ASCII 32)

  for (int x = 16; x > block; x--) {  // Imprimir todos los bloques en blanco
    lcd.setCursor(x, row);
    lcd.write(32);  // Espacio en blanco (ASCII 32)
  }
}

// Función para hacer sonar el buzzer
void beep(unsigned char pausa) {
  analogWrite(BUZZER, 500);
  delay(pausa);
  analogWrite(BUZZER, 0);
  delay(pausa);
}

No hay comentarios:

Publicar un comentario

Nota: solo los miembros de este blog pueden publicar comentarios.

Medidor de potencia y roe

 Este proyecto consiste en la construcción de un medidor de potencia y ROE digital, utilizando un Arduino Nano y una pantalla LCD 20x4 con i...