/*
Use a canvas to stop display flicker when updating.
Partly successful. Display updates without flicker but update is very slow.
Update appears to be in situ eather than page swapping.
Even slower with a black and white bitmap???
Had to set canvas size to half the display size to avoid crashes. Memory?
*/
#include <Adafruit_GFX.h>
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
// #include <Fonts/FreeSansBold24pt7b.h>
// Display pin definitions
#define TFT_BL 21 // Backlight
#define TFT_SCLK 18 // 14
#define TFT_MOSI 23 // 13
#define TFT_MISO 15 // 12
#define TFT_DC 2
#define TFT_CS 5 // 15
#define TFT_RST 4 // -1 // No reset defined
#define ST77XX_DARKGRAY 0x7bef // Not defined in Adafruit graphics
#define ST77XX_LIGHTGRAY 0xb5d6
Adafruit_ST7789 display = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
// Set canvas size to half screen size
GFXcanvas16 canvas(160, 170); // Half width (320) full height(170)
// GFXcanvas1 canvas(160, 170); // Half width (320) full height(170)
unsigned int charWidth = 6, charHeight = 8, charSize = 4;
// unsigned int hdg = 30; //int(random(360));
unsigned int RotX(int a, int b, float S, float C) // Rotate and offset x coordinate
{
// return (unsigned int)(a * C - b * S + display.width() * 3 / 4 - 1); // Centred on right half
return (unsigned int)(a * C - b * S + display.width() / 4 - 1); // Centred on right half
}
unsigned int RotY(int a, int b, float S, float C) // Rotate and offset y coordinate
{
return (unsigned int)(a * S + b * C + display.height() / 2 - 1); // Half way down display
}
char* getSector(float H)
{
// Select a sector on the compass rose that contains the heading
static char Sector[4] = {'\0'};
// Sixteen overlapping segments
if (H > 348.5 || H < 11.5) // Top of compass
strcpy(Sector, "N");
else if (H > 11 && H < 34)
strcpy(Sector, "NNE");
else if (H > 33.5 && H < 56.5)
strcpy(Sector, "NE");
else if (H > 56 && H < 79)
strcpy(Sector, "ENE");
else if (H > 78.5 && H < 101.5)
strcpy(Sector, "E");
else if (H > 101 && H < 124)
strcpy(Sector, "ESE");
else if (H > 123.5 && H < 146.5)
strcpy(Sector, "SE");
else if (H > 146 && H < 169)
strcpy(Sector, "SSE");
else if (H > 168.5 && H < 191.5)
strcpy(Sector, "S");
else if (H > 191 && H < 214)
strcpy(Sector, "SSW");
else if (H > 213.5 && H < 236.5)
strcpy(Sector, "SW");
else if (H > 236 && H < 259)
strcpy(Sector, "WSW");
else if (H > 258.5 && H < 281.5)
strcpy(Sector, "W");
else if (H > 281 && H < 304)
strcpy(Sector, "WNW");
else if (H > 303.5 && H < 326.5)
strcpy(Sector, "NW");
else if (H > 326 && H < 349)
strcpy(Sector, "NNW");
else
strcpy(Sector, "WTF");
return Sector;
}
void updateDisplay(int Heading)
{
const int NeedleHeight = canvas.height() / 2 - 6;
const int NeedleWidth = NeedleHeight / 5;
const unsigned int Radius = canvas.width() / 2 - 1;
const unsigned int Xoffset = Radius;
const unsigned int Yoffset = Radius;
const int a1 = 0, b1 = NeedleHeight;
const int a2 = -NeedleWidth, b2 = 0;
const int a3 = 0, b3 = -NeedleHeight;
const int a4 = NeedleWidth, b4 = 0;
unsigned int x1, y1, x2, y2, x3, y3, x4, y4; // Vertices of needle to be drawn
unsigned int Offset;
//Draw heading
float H = Heading * PI / 180; // Convert to radians for rotation
char* SectorStr;
// charSize = 2;
charSize = 5;
canvas.setTextWrap(false);
canvas.fillScreen(ST77XX_WHITE); // Clear canvas
canvas.setTextSize(charSize);
canvas.setTextColor(ST77XX_BLACK);
SectorStr = getSector(Heading);
// Centred one and a half characters in. Assumes 32 high x 24 wide characters
Offset = 3 * charWidth * charSize / 2 - ((strlen(SectorStr) * charSize * charWidth) / 2);
canvas.setCursor(Offset + 4, charHeight * charSize / 2); // Top line
// canvas.setCursor(Offset + 4, 40 ); // Kludge for font
canvas.println(SectorStr);
// canvas.setCursor(4 + charWidth * charSize,
// display.height() / 2 - charSize * charHeight / 2 ); // Middle line
canvas.setCursor(canvas.getCursorX() + charWidth * charSize, canvas.getCursorY()); // Middle line
canvas.println('\\'); // backslash
// canvas.setCursor(4, canvas.height() - 3 * charHeight * charSize / 2); // Bottom line
// canvas.setCursor(4, 160); // Bottom line
canvas.setCursor(canvas.getCursorX() + 4, canvas.getCursorY()); // Bottom line
if (Heading < 100) canvas.print(0); // Add leading zeroes as required
if (Heading < 10) canvas.print(0);
canvas.print(Heading);
display.drawRGBBitmap(0, 0, canvas.getBuffer(), canvas.width(), canvas.height());
// display.drawBitmap(0, 0, canvas.getBuffer(), canvas.width(), canvas.height(), ST77XX_WHITE, ST77XX_BLACK);
// Draw the compass
if (H > 0.0) H = 2 * PI - H; // Flip to always point north
float S = sin(H);
float C = cos(H);
// Rotate needle away from north by Heading degrees
x1 = RotX(a1, b1, S, C);
y1 = RotY(a1, b1, S, C);
x2 = RotX(a2, b2, S, C);
y2 = RotY(a2, b2, S, C);
x3 = RotX(a3, b3, S, C);
y3 = RotY(a3, b3, S, C);
x4 = RotX(a4, b4, S, C);
y4 = RotY(a4, b4, S, C);
canvas.fillScreen(ST77XX_WHITE); // Clear canvas
canvas.drawTriangle(x1, y1, x2, y2, x4, y4, ST77XX_BLACK); // South half outlined
canvas.fillTriangle(x1, y1, x2, y2, Xoffset, Yoffset, ST77XX_LIGHTGRAY); // South half shaded
canvas.fillTriangle(x2, y2, x3, y3, x4, y4, ST77XX_BLACK); // North half filled
canvas.fillTriangle(x2, y2, x3, y3, Xoffset, Yoffset, ST77XX_DARKGRAY); // North half shaded
canvas.drawCircle(Xoffset, Yoffset + 2, Radius, ST77XX_BLACK); // x,y,r
canvas.drawCircle(Xoffset, Yoffset + 2, Radius - 1, ST77XX_BLACK); // Double thickness circle
display.drawRGBBitmap(canvas.width(), 0, canvas.getBuffer(), canvas.width(), canvas.height());
// display.drawBitmap(canvas.width(), 0, canvas.getBuffer(), canvas.width(), canvas.height(), ST77XX_WHITE, ST77XX_BLACK);
}
void setup()
{
display.init(170, 320);
display.setRotation(3); // Landscape with USB on right
// canvas.setFont(&FreeSerifBold24pt7b); // Use custom font
// canvas.setFont(&FreeSansBold24pt7b); // Use custom font
canvas.setTextWrap(false); // Clip text within canvas
Serial.begin(115200);
Serial.println("ESP32TFTcompassDisplayTestCanvas.ino");
Serial.println("Initialising...");
pinMode(TFT_BL, OUTPUT); // Turn on backlight
digitalWrite(TFT_BL, HIGH);
Serial.println("Displaying last fix");
display.fillScreen(ST77XX_WHITE); // Clear screen
display.setTextColor(ST77XX_BLACK);
display.setTextSize(charSize);
display.setCursor(0, 0);
display.println("Last fix:");
display.println(-33.70244, 5); // 9 characters
display.println(151.09931, 5); // 10 characters
display.println(12.43, 2); // 5 characters
delay(2000);
display.fillScreen(ST77XX_WHITE);
}
void loop()
{
static bool Inverted = false;
// updateDisplay(random(10)-random(5) + hdg);
// updateDisplay(hdg + random(10 - random(5)));
// frabble();
// delay(200);
display.invertDisplay(Inverted);
Inverted = !Inverted;
delay(5000);
}