SB-200 Plate Meter Design with GC9A01 & Arduino Nano
SB-200 Plate Meter Design with GC9A01 & Arduino Nano
This design replaces the analog meter in your Heathkit SB-200 with a digital gauge on a 1.28" GC9A01 Round TFT. It measures plate current via a shunt resistor and displays it on a colorful, animated dial.
1. Hardware Connections
Critical Warning: The GC9A01 is a 3.3V logic device. The Arduino Nano is 5V. You must use a logic level converter or series resistors (220Ω–330Ω) on the SPI lines (MOSI, SCK, CS, DC) to prevent damage.
GC9A01 Pin Arduino Nano Pin Note
VCC 3.3V Do NOT use 5V
GND GND Common Ground
CS D10 Chip Select
DC D9 Data/Command
SDA (MOSI) D11 Data In (Use 220Ω resistor)
SCL (SCK) D13 Clock (Use 220Ω resistor)
RST D8 Reset (Optional, can tie to 3.3V if not used in code)
BL 3.3V Backlight (Or PWM pin for dimming)
Current Sensing Circuit (Shunt): The SB-200 cathode current (Plate + Grid) flows to ground. Insert a low-value shunt resistor in the cathode ground path.
Shunt Value: 0.1Ω to 0.5Ω (5W+ Wirewound).
At 500mA (0.5A), a 0.1Ω shunt drops 0.05V (50mV).
At 500mA, a 0.5Ω shunt drops 0.25V (250mV).
Recommendation: Use 0.22Ω @ 5W.
Max Drop: $0.5A \times 0.22\Omega = 0.11V$ (110mV). This is safe for the tube bias but requires amplification or careful ADC reading.
Wiring: Connect the shunt between the tube cathodes and the amplifier chassis ground. Connect the Arduino A0 to the tube side of the shunt and GND to the chassis side.
Note: The Arduino reads 0–1023 for 0–5V. 110mV is only ~22 counts. For better resolution, use the Internal 1.1V Reference (analogReference(INTERNAL)), which gives ~930 counts for 110mV.
Arduino Nano current shunt sensing circuit
View all
2. Required Libraries
Install these via the Arduino Library Manager:
Adafruit GFX Library
Adafruit GC9A01A Library (or GC9A01 by Bodmer if preferred)
3. Arduino Code
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_GC9A01A.h>
// --- Pin Definitions ---
#define TFT_CS 10
#define TFT_DC 9
#define TFT_RST 8
#define SHUNT_PIN A0
// --- Configuration ---
#define SHUNT_RESISTANCE 0.22 // Ohms (Change to match your shunt)
#define MAX_CURRENT_MA 600 // Full scale deflection (mA)
#define REF_VOLTAGE 1.1 // Internal reference voltage (1.1V for better resolution)
// Initialize Display
Adafruit_GC9A01A tft = Adafruit_GC9A01A(TFT_CS, TFT_DC, TFT_RST);
// Gauge Geometry
#define CENTER_X 120
#define CENTER_Y 120
#define RADIUS 100
#define GAUGE_START_ANGLE 150 // Degrees (Left bottom)
#define GAUGE_END_ANGLE 390 // Degrees (Right bottom, wraps around)
void setup() {
Serial.begin(9600);
// Use Internal 1.1V Reference for higher resolution on small voltages
analogReference(INTERNAL);
tft.begin();
tft.fillScreen(GC9A01A_BLACK);
tft.setRotation(2); // Adjust based on USB port orientation
// Draw Static Gauge Background
drawGaugeBackground();
}
void loop() {
// Read ADC (0-1023 for 0-1.1V)
int sensorValue = analogRead(SHUNT_PIN);
// Convert to Voltage (1.1V ref)
float voltage = sensorValue * (REF_VOLTAGE / 1023.0);
// Convert to Current (Ohm's Law: I = V/R)
float currentA = voltage / SHUNT_RESISTANCE;
float currentMA = currentA * 1000.0;
// Clamp values
if (currentMA < 0) currentMA = 0;
if (currentMA > MAX_CURRENT_MA) currentMA = MAX_CURRENT_MA;
// Draw Needle
drawNeedle(currentMA);
// Display Numeric Value
displayNumericValue(currentMA);
delay(100); // Update rate
}
void drawGaugeBackground() {
// Outer Ring
tft.drawCircle(CENTER_X, CENTER_Y, RADIUS, GC9A01A_WHITE);
tft.drawCircle(CENTER_X, CENTER_Y, RADIUS - 5, GC9A01A_WHITE);
// Scale Ticks
for (int i = 0; i <= MAX_CURRENT_MA; i += 50) {
float angle = map(i, 0, MAX_CURRENT_MA, GAUGE_START_ANGLE, GAUGE_END_ANGLE);
int x1 = CENTER_X + (RADIUS - 10) * cos(radians(angle));
int y1 = CENTER_Y + (RADIUS - 10) * sin(radians(angle));
int x2 = CENTER_X + (RADIUS - 20) * cos(radians(angle));
int y2 = CENTER_Y + (RADIUS - 20) * sin(radians(angle));
if (i % 100 == 0) {
tft.drawLine(x1, y1, x2, y2, GC9A01A_WHITE); // Major tick
// Draw Numbers (Simplified positioning)
tft.setCursor(CENTER_X + (RADIUS - 35) * cos(radians(angle)),
CENTER_Y + (RADIUS - 35) * sin(radians(angle)));
tft.setTextColor(GC9A01A_WHITE);
tft.setTextSize(1);
tft.print(i/100); // Print 0, 1, 2...
} else {
tft.drawLine(x1, y1, x2, y2, GC9A01A_GRAY); // Minor tick
}
}
// Center Label
tft.setCursor(CENTER_X - 20, CENTER_Y + 40);
tft.setTextColor(GC9A01A_GREEN);
tft.setTextSize(2);
tft.print("mA");
}
void drawNeedle(float currentMA) {
static float lastAngle = -1;
float angle = map(currentMA, 0, MAX_CURRENT_MA, GAUGE_START_ANGLE, GAUGE_END_ANGLE);
// Simple erase/redraw (could be optimized with XOR or buffer)
// Clear previous needle (draw over with background color)
if (lastAngle >= 0) {
int x1 = CENTER_X + (RADIUS - 25) * cos(radians(lastAngle));
int y1 = CENTER_Y + (RADIUS - 25) * sin(radians(lastAngle));
tft.drawLine(CENTER_X, CENTER_Y, x1, y1, GC9A01A_BLACK);
}
// Draw new needle
int x2 = CENTER_X + (RADIUS - 25) * cos(radians(angle));
int y2 = CENTER_Y + (RADIUS - 25) * sin(radians(angle));
// Color changes based on current (Green -> Yellow -> Red)
uint16_t needleColor = GC9A01A_GREEN;
if (currentMA > 400) needleColor = GC9A01A_YELLOW;
if (currentMA > 550) needleColor = GC9A01A_RED;
tft.drawLine(CENTER_X, CENTER_Y, x2, y2, needleColor);
tft.fillCircle(CENTER_X, CENTER_Y, 5, GC9A01A_WHITE); // Center cap
lastAngle = angle;
}
void displayNumericValue(float currentMA) {
// Clear old number area
tft.fillRect(80, 160, 80, 30, GC9A01A_BLACK);
tft.setCursor(90, 165);
tft.setTextColor(GC9A01A_CYAN);
tft.setTextSize(2);
tft.print(currentMA, 0); // Print integer
}
4. Calibration & Safety
Calibration: Transmit a carrier into a dummy load. Adjust the SHUNT_RESISTANCE value in the code until the display matches a trusted external multimeter reading.
Safety: The shunt resistor is at RF Ground, but ensure the Arduino is powered by an isolated USB source (laptop battery or isolated supply) to prevent ground loops or RF feedback into the USB port.
Filtering: Add a 0.1µF capacitor across the shunt resistor to filter RF noise from the ADC reading.
Comments
Post a Comment