// Demo using arcFill to draw ellipses and a segmented elipse
//#include <TFT_eSPI.h> // Hardware-specific library
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#include <SPI.h>
//TFT_eSPI tft = TFT_eSPI(); // Invoke custom library
#define TFT_DC 21
#define TFT_CS 22
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
#define DEG2RAD 0.0174532925
#define LOOP_DELAY 10 // Loop delay to slow things down
#define ENCODER_CLK 14
#define ENCODER_DT 12
#define ENCODER_SW 13
#define RED2RED 0
#define GREEN2GREEN 1
#define BLUE2BLUE 2
#define BLUE2RED 3
#define GREEN2RED 4
#define RED2GREEN 5
int counter = 0;
byte inc = 0;
unsigned int col = 0;
byte red = 31; // 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 state = 0;
int tempValue = 0;
void setup(void) {
pinMode(ENCODER_CLK, INPUT);
pinMode(ENCODER_DT, INPUT);
pinMode(ENCODER_SW, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), readEncoder, FALLING);
tft.begin();
tft.setRotation(1);
// tft.fillScreen(TFT_BLACK);
tft.fillScreen(ILI9341_BLACK);
}
void loop() {
tempValue = getCounter();
// fillArc(160, 120, tempValue * 6, 1, 120, 120, 10, rainbow(col));
ringMeter(tempValue*5,0,200, 40, 5, 120," C",GREEN2RED); // Draw analogue meter
/*
// Continuous elliptical arc drawing
//fillArc(160, 120, inc * 6, 1, 140, 100, 10, rainbow(col));
// Continuous segmented (inc*2) elliptical arc drawing
//fillArc(160, 120, ((inc * 2) % 60) * 6, 1, 120, 80, 30, rainbow(col));
fillArc(160, 120, ((inc * 3) % 60) * 6, 1, 120, 120, 10, rainbow(col));
// Circle drawing using arc with arc width = radius
//fillArc(160, 120, inc * 6, 1, 42, 42, 42, rainbow(col));
inc++;
col += 1;
if (col > 191) col = 0;
if (inc > 59) inc = 0;
delay(LOOP_DELAY);
*/
}
void readEncoder() {
int dtValue = digitalRead(ENCODER_DT);
if (dtValue == HIGH) {
counter++; // Clockwise
}
if (dtValue == LOW) {
counter--; // Counterclockwise
}
}
// Get the counter value, disabling interrupts.
// This make sure readEncoder() doesn't change the value
// while we're reading it.
int getCounter() {
int result;
noInterrupts();
result = counter;
interrupts();
return result;
}
void resetCounter() {
noInterrupts();
counter = 0;
interrupts();
}
// #########################################################################
// Draw a circular or elliptical arc with a defined thickness
// #########################################################################
// x,y == coords of centre of arc
// start_angle = 0 - 359
// seg_count = number of 6 degree segments to draw (60 => 360 degree arc)
// rx = x axis outer radius
// ry = y axis outer radius
// w = width (thickness) of arc in pixels
// colour = 16 bit colour value
// Note if rx and ry are the same then an arc of a circle is drawn
void fillArc(int x, int y, int start_angle, int seg_count, int rx, int ry, int w, unsigned int colour)
{
byte seg = 6; // Segments are 3 degrees wide = 120 segments for 360 degrees
byte inc = 6; // Draw segments every 3 degrees, increase to 6 for segmented ring
// Calculate first pair of coordinates for segment start
float sx = cos((start_angle - 90) * DEG2RAD);
float sy = sin((start_angle - 90) * DEG2RAD);
uint16_t x0 = sx * (rx - w) + x;
uint16_t y0 = sy * (ry - w) + y;
uint16_t x1 = sx * rx + x;
uint16_t y1 = sy * ry + y;
// Draw colour blocks every inc degrees
for (int i = start_angle; i < start_angle + seg * seg_count; i += inc) {
// Calculate pair of coordinates for segment end
float sx2 = cos((i + seg - 90) * DEG2RAD);
float sy2 = sin((i + seg - 90) * DEG2RAD);
int x2 = sx2 * (rx - w) + x;
int y2 = sy2 * (ry - w) + y;
int x3 = sx2 * rx + x;
int y3 = sy2 * ry + y;
tft.fillTriangle(x0, y0, x1, y1, x2, y2, colour);
tft.fillTriangle(x1, y1, x2, y2, x3, y3, colour);
// Copy segment end to sgement start for next segment
x0 = x2;
y0 = y2;
x1 = x3;
y1 = y3;
}
}
// #########################################################################
// Return the 16 bit colour with brightness 0-100%
// #########################################################################
unsigned int brightness(unsigned int colour, int brightness)
{
byte red = colour >> 11;
byte green = (colour & 0x7E0) >> 5;
byte blue = colour & 0x1F;
blue = (blue * brightness) / 100;
green = (green * brightness) / 100;
red = (red * brightness) / 100;
return (red << 11) + (green << 5) + blue;
}
// #########################################################################
// Return a 16 bit rainbow colour
// #########################################################################
unsigned int rainbow1(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
switch (state) {
case 0:
green ++;
if (green == 64) {
green = 63;
state = 1;
}
break;
case 1:
red--;
if (red == 255) {
red = 0;
state = 2;
}
break;
case 2:
blue ++;
if (blue == 32) {
blue = 31;
state = 3;
}
break;
case 3:
green --;
if (green == 255) {
green = 0;
state = 4;
}
break;
case 4:
red ++;
if (red == 32) {
red = 31;
state = 5;
}
break;
case 5:
blue --;
if (blue == 255) {
blue = 0;
state = 0;
}
break;
}
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, char *units, byte scheme)
{
// 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 / 12; // Width of outer ring is 1/4 of radius
int angle = 150; // Half the sweep angle of meter (300 degrees)
int text_colour = 0; // To hold the text colour
int v = map(value, vmin, vmax, -angle, angle); // Map the value to an angle v
byte seg = 10; // Segments are 5 degrees wide = 60 segments for 300 degrees
byte inc = 12; // Draw segments every 5 degrees, increase to 10 for segmented ring
// Draw colour blocks every inc degrees
for (int i = -angle; i < angle; i += inc) {
// Choose colour from scheme
int colour = 0;
switch (scheme) {
case 0: colour = ILI9341_RED; break; // Fixed colour
case 1: colour = ILI9341_GREEN; break; // Fixed colour
case 2: colour = ILI9341_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, 85, 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 = ILI9341_BLUE; break; // Fixed colour
}
// 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) { // Fill in coloured segments with 2 triangles
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
}
else // Fill in blank segments
{
tft.fillTriangle(x0, y0, x1, y1, x2, y2, 128);
tft.fillTriangle(x1, y1, x2, y2, x3, y3, 128);
}
}
// Convert value to a string
char buf[10];
byte len = 4; if (value > 999) len = 5;
dtostrf(value, len, 0, buf);
// Set the text colour to default
//tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
// Uncomment next line to set the text colour to the last segment value!
// tft.setTextColor(text_colour, ILI9341_BLACK);
// Print value, if the meter is large then use big font 6, othewise use 4
//if (r > 84) tft.drawCentreString(buf, x - 5, y - 20, 6); // Value in middle
//else tft.drawCentreString(buf, x - 5, y - 20, 4); // Value in middle
// Print units, if the meter is large then use big font 4, othewise use 2
//tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
//if (r > 84) tft.drawCentreString(units, x, y + 30, 4); // Units display
//else tft.drawCentreString(units, x, y + 5, 2); // Units display
// Calculate and return right hand side x coordinate
return x + r;
}
// #########################################################################
// 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;
}
// #########################################################################
// Return a value in range -1 to +1 for a given phase angle in degrees
// #########################################################################
float sineWave(int phase) {
return sin(phase * 0.0174532925);
}