When it comes to build a case for your project it turns out that analog meters require a deep box.
Fig. 1: analog meter
That is why I decided to use a small TFT display to replace it. And it can be programmed to adjust the range automatically.
Fig. 2: range set to 5 volts
Fig. 3: range set ro 2.5 volts
Select whether you want to apply a maximum of 5 volts or 10 volts.
/*
simulate an analog voltmeter
Define the range you want to use.
If you are fine with 5 volts
use #define R5 either don't.
If you want to input 10 volts
at A0 use two equal resistors
to get a 2 to 1 voltage divider.
*/
#define R5
//#define DEMO // random values
//#define CONTROL // digital values shown
#include <TFT.h>
#define cs 10
#define dc 9
#define rst 8
const word WHITE = 0xFFFF;
const word BLACK = 0;
const word RED = 0xF800;
const word BLUE = 0x001F;
const word GREEN = 0x07E0;
const word GILB = 0x73EF; //
const word BLEU = 0x7BE0;
const word Color = 0x1234;
const float PI34 = PI * 3 / 4;
int w, h, mx, my, v, t1;
int x4, y4, x5, y5, r1, r3, r4, r5;
#ifdef R5
const int maxVolt = 5;
#else
const int maxVolt = 10;
#endif
float bereich;
float oldRange = maxVolt;
TFT tft = TFT(cs, dc, rst);
void setup() {
Serial.begin(9600);
Serial.println(__FILE__);
tft.begin();
w = tft.width();
h = tft.height();
#ifdef R5
mx = w / 2 + 5;
my = 105;
t1 = 4;
//int bereich = 2 - 5 Volt
r1 = 75;
r3 = 102;
#else
mx = w / 2 - 1;
my = 100;
t1 = 6;
//int bereich = 2 - 5 - 10 Volt
r1 = 70;
r3 = 97;
#endif
r4 = 20;
x4 = mx;
y4 = my;
x5 = x4;
y5 = y4;
tft.setRotation(3);
tft.setTextSize(2);
frontplatte(maxVolt); // <--- Bereich 5/10 Volt
}
void loop() {
#ifdef DEMO
v = random(1024);
#else
v = analogRead(A0);
#endif
bereich = range(v);
if (bereich != oldRange) {
frontplatte(bereich);
oldRange = bereich;
}
zeiger(v);
delay(10);
}
void skala(float bereich) {
r5 = r1 - 2;
float steps = 50; // <---
float phi;
// zeichne Skala im Uhrzeigersinn:
int x0 = mx + r1 * cos(PI34);
int y0 = my - r1 * sin(PI34);
for (int v = 0; v <= 100; v = v + 5) {
phi = PI34 * (1 - v / (3 * steps));
int x1 = mx + r1 * cos(phi);
int y1 = my - r1 * sin(phi);
tft.drawLine(x0, y0, x1, y1, BLACK);
x0 = x1;
y0 = y1;
int r2;
// lang oder kurz?
boolean tick = v % 10 == 0;
if (tick) r2 = r1 + 10; else r2 = r1 + 5;
int x2 = mx + r2 * cos(phi);
int y2 = my - r2 * sin(phi);
tft.drawLine(x1, y1, x2, y2, BLACK);
if ((v % 20) != 0) continue;
if ((bereich == 2.5) && (v % 40 != 0)) continue;
// zeichne DICKE Linie:
tft.drawLine(x1 + 1, y1, x2 + 1, y2, BLACK);
int x3 = mx + r3 * cos(phi) - 5;
int y3 = my - r3 * sin(phi);
if (v < 100) tft.setCursor(x3, y3);
else tft.setCursor(x3 - 7, y3);
tft.stroke(BLACK);
tft.print(v * bereich / 100, 0);
}
}
void zeiger(int u) {
// ----------------
#ifdef CONTROL
tft.fillRect(6, 6, 24, 8, WHITE);
tft.setCursor(6, 6);
tft.setTextSize(1);
tft.print(u);
tft.setTextSize(2);
#endif
//-----------------
// alten Zeiger loeschen:
for (int b = 0; b < 2; b++)
tft.drawLine(x4 + b, y4, x5 + b, y5, GILB);
// neuen Zeiger zeichnen:
float phi = PI34 - HALF_PI * u / 1024 * maxVolt / bereich;
x4 = mx + r4 * cos(phi);
y4 = my - r4 * sin(phi);
x5 = mx + r5 * cos(phi);
y5 = my - r5 * sin(phi);
for (int b = 0; b < 2; b++)
tft.drawLine(x4 + b, y4, x5 + b, y5, BLUE);
tft.stroke(BLACK);
tft.text("V", w / 2 - 5, 50); // Volt
}
void frontplatte(float b) {
tft.background(GILB);
skala(b);
int r = 10;
tft.drawRoundRect(0, 0, w, h, r, RED);
tft.drawRoundRect(0, 0, w, h, r + 1, RED);
tft.drawRoundRect(1, 1, w - 2, h - 2, r - 1, RED);
tft.fillRoundRect(2, my, w - 4, h - my - 2, r - 2, BLACK);
tft.fillRect(2, my, w - 4, (h - my - 2) / 2, BLACK);
tft.fillCircle(mx, my, r4, BLACK); // mx, my, r
tft.stroke(WHITE);
tft.text("AUTORANGE", 30, my + t1);
}
float range(int v) {
switch (v) {
#ifdef R5
case 0 ... 511: return 2.5;
#else
case 0 ... 255: return 2.5;
case 256 ... 511: return 5;
#endif
case 512 ... 1023: return maxVolt;
}
}
Comments
Please log in or sign up to comment.