Mirko Pavleski
Published © GPL3+

DIY Shortwave Propagation Monitor - Measure Ionosphere

Learn how to make a simple device for monitoring the state of the ionosphere and the quality of shortwave signals using the CA3089 chip.

BeginnerFull instructions provided2 hours65
DIY Shortwave Propagation Monitor - Measure Ionosphere

Things used in this project

Hardware components

CA3089 IC
×1
Arduino Nano R3
Arduino Nano R3
×1
SSD1306 Oled Display 0.96"
×1
Passive components (resistors, capacitors)
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Solder Wire, Lead Free
Solder Wire, Lead Free

Story

Read more

Schematics

Schematic

...

Code

Code

C/C++
..
//  by mircemk  April, 2026

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

// ---- UI (поголем BOX долу) ----
const int BAR_Y = 2;
const int BAR_H = 12;
const int BAR_X = 2;
const int BAR_W = 124;

const int BOX_X = 6;     // помал margin
const int BOX_Y = 20;    // спуштено нагоре малку
const int BOX_W = 116;   // пошироко
const int BOX_H = 44;    // повисоко (скоро до дното)
const int BOX_R = 8;

// ---- Analog ----
const int ANALOG_PIN = A0;

// ======= РАНГ (ADC) =======
int IN_MIN = 60;
int IN_MAX = 1000;

static inline int clampInt(int v, int lo, int hi) {
  if (v < lo) return lo;
  if (v > hi) return hi;
  return v;
}

static inline int mapLongToInt(long x, long in_min, long in_max, long out_min, long out_max) {
  if (in_max == in_min) return (int)out_min;
  return (int)((x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min);
}

void drawCenteredTextInBox(const char* txt, int textSize) {
  display.setTextSize(textSize);

  int16_t x1, y1;
  uint16_t w, h;
  display.getTextBounds(txt, 0, 0, &x1, &y1, &w, &h);

  int tx = BOX_X + (BOX_W - (int)w) / 2;
  int ty = BOX_Y + (BOX_H - (int)h) / 2;

  display.setCursor(tx, ty);
  display.print(txt);
}

void setup() {
  analogReference(DEFAULT);
  Wire.begin();

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    while (1) {}
  }
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.display();
}

void loop() {
  int raw = analogRead(ANALOG_PIN);

  int a = IN_MIN, b = IN_MAX;
  if (a > b) { int t = a; a = b; b = t; }

  int rawWin = clampInt(raw, a, b);

  int rel1000 = mapLongToInt(rawWin, a, b, 0, 1000);
  int barFill = mapLongToInt(rawWin, a, b, 0, BAR_W);

  display.clearDisplay();

  // BAR
  display.drawRect(BAR_X, BAR_Y, BAR_W, BAR_H, SSD1306_WHITE);
  int innerW = barFill - 2;
  if (innerW < 0) innerW = 0;
  if (innerW > BAR_W - 2) innerW = BAR_W - 2;
  display.fillRect(BAR_X + 1, BAR_Y + 1, innerW, BAR_H - 2, SSD1306_WHITE);

  // BOX
  display.drawRoundRect(BOX_X, BOX_Y, BOX_W, BOX_H, BOX_R, SSD1306_WHITE);

  // број (auto size: 0-999 големо, 1000 помало)
  char buf[6];
  snprintf(buf, sizeof(buf), "%d", rel1000);

  int size = (rel1000 >= 1000) ? 3 : 4;  // 1000 да собере
  drawCenteredTextInBox(buf, size);

  display.display();
  delay(1000);
}

Credits

Mirko Pavleski
222 projects • 1594 followers

Comments