#include "Free_Fonts.h" // Include the header file attached to this sketch
#include <TFT_eSPI.h>
#include <TFT_eWidget.h>
#include <SPI.h>
#include "FreqCountESP.h"
// Meter colour schemes
#define RED2RED 0
#define GREEN2GREEN 1
#define BLUE2BLUE 2
#define BLUE2RED 3
#define GREEN2RED 4
#define RED2GREEN 5
#define TFT_GREY 0x2104 // Dark grey 16-bit colour
#define LOOP_PERIOD 100 // Display updates every 100 ms
int colour = TFT_BLUE;
TFT_eSPI tft = TFT_eSPI();
// Return a 16-bit rainbow colour
unsigned int rainbow(byte value) {
// Value is expected to be in range 0-127
// The value is converted to a spectrum colour from 0 = blue through to 127 = red
byte red = 0; // Red is the top 5 bits of a 16-bit colour value
byte green = 0;// Green is the middle 6 bits
byte blue = 0; // Blue is the bottom 5 bits
byte quadrant = value / 32;
if (quadrant == 0) {
blue = 31;
green = 2 * (value % 32);
red = 0;
}
if (quadrant == 1) {
blue = 31 - (value % 32);
green = 63;
red = 0;
}
if (quadrant == 2) {
blue = 0;
green = 63;
red = value % 32;
}
if (quadrant == 3) {
blue = 0;
green = 63 - 2 * (value % 32);
red = 31;
}
return (red << 11) + (green << 5) + blue;
}
// Draw the meter on the screen, returns x coord of righthand side
int ringMeter(int value, int vmin, int vmax, int x, int y, int r, const char *units, byte scheme, int flag) {
// Minimum value of r is about 52 before value text intrudes on ring
// drawing the text first is an option
x += r; y += r; // Calculate coords of centre of ring
int w = r / 3; // Width of outer ring is 1/4 of radius
int angle = 180; // Half the sweep angle of meter (300 degrees)
int v = map(value, vmin, vmax, -angle, angle); // Map the value to an angle v
byte seg = 3; // Segments are 3 degrees wide = 100 segments for 300 degrees
byte inc = 6; // Draw segments every 3 degrees, increase to 6 for segmented ring
// Variable to save "value" text colour from scheme and set default
colour = TFT_BLUE;
// Draw colour blocks every inc degrees
for (int i = -angle + inc / 2; i < angle - inc / 2; i += inc) {
// Calculate pair of coordinates for segment start
float sx = cos((i - 90) * 0.0174532925);
float sy = sin((i - 90) * 0.0174532925);
uint16_t x0 = sx * (r - w) + x;
uint16_t y0 = sy * (r - w) + y;
uint16_t x1 = sx * r + x;
uint16_t y1 = sy * r + y;
// Calculate pair of coordinates for segment end
float sx2 = cos((i + seg - 90) * 0.0174532925);
float sy2 = sin((i + seg - 90) * 0.0174532925);
int x2 = sx2 * (r - w) + x;
int y2 = sy2 * (r - w) + y;
int x3 = sx2 * r + x;
int y3 = sy2 * r + y;
if ((i < v) && (flag == 0)) { // Fill in coloured segments with 2 triangles
switch (scheme) {
case 0: colour = TFT_RED; break; // Fixed colour
case 1: colour = TFT_GREEN; break; // Fixed colour
case 2: colour = TFT_BLUE; break; // Fixed colour
case 3: colour = rainbow(map(i, -angle, angle, 0, 127)); break; // Full spectrum blue to red
case 4: colour = rainbow(map(i, -angle, angle, 70, 127)); break; // Green to red (high temperature etc.)
case 5: colour = rainbow(map(i, -angle, angle, 127, 63)); break; // Red to green (low battery etc.)
default: colour = TFT_BLUE; break; // Fixed colour
}
tft.fillTriangle(x0, y0, x1, y1, x2, y2, colour);
tft.fillTriangle(x1, y1, x2, y2, x3, y3, colour);
//text_colour = colour; // Save the last colour drawn
// Fill in blank segments if flag = 1
} else {
tft.fillTriangle(x0, y0, x1, y1, x2, y2, TFT_GREY);
tft.fillTriangle(x1, y1, x2, y2, x3, y3, TFT_GREY);
}
}
// Convert value to a string
char buf[10];
byte len = 3;
if (value > 999)
len = 7;
dtostrf(value, len, 0, buf);
buf[len] = ' ';
buf[len + 1] = 0; // Add blanking space and terminator, helps to centre text too!
// Set the text colour to default
tft.setTextSize(0);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
// Uncomment next line to set the text colour to the last segment value!
tft.setTextColor(colour, TFT_BLACK);
tft.setTextDatum(MC_DATUM);
// Print value, if the meter is large then use big font 8, othewise use 4
if (r > 84) {
tft.setTextPadding(55 * 2); // Allow for 3 digits each 55 pixels wide
tft.drawString(buf, x, y, 4); // Value in middle
} else {
tft.setTextPadding(3 * 14); // Allow for 3 digits each 14 pixels wide
tft.drawString(buf, x, y, 4); // Value in middle
}
tft.setTextSize(0);
tft.setTextPadding(0);
// Print units, if the meter is large then use big font 4, othewise use 2
tft.setTextColor(TFT_WHITE, TFT_BLACK);
// if (r > 84) tft.drawString(units, x, y + 60, 4); // Units display
// else tft.drawString(units, x, y + 15, 2); // Units display
tft.drawString(units, x, y + 25, 4);
// Calculate and return right hand side x coordinate
return x + r;
}
uint32_t frequency = 0;
static const int inputPin = 33;
int timerMs = 1000;
static const int minimumFrequency = 1; // (HZ)
static const int maximumFrequency = 1000000; // (HZ)
void setup() {
Serial.begin(115200);
delay(2000);
tft.begin();
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
tft.setFreeFont(FF18);
FreqCountESP.begin(inputPin, timerMs);
}
void loop() {
if (FreqCountESP.available()) {
frequency = FreqCountESP.read();
Serial.println(frequency);
}
// Set the the position, gap between meters, and inner radius of the meters
int xpos = 0, ypos = 5, gap = 4, radius = 52;
// Draw a large meter
xpos = 480 / 2 - 160, ypos = 0, gap = 15, radius = 100;
// Comment out above meters, then uncomment the next line to show large meter
ringMeter(frequency, minimumFrequency, maximumFrequency, xpos, ypos, radius, " Hz", BLUE2RED, 0); // Draw analogue meter
}