commit
153afebb1f
4 changed files with 875 additions and 2 deletions
178
Adafruit_ST7796S.cpp
Normal file
178
Adafruit_ST7796S.cpp
Normal file
|
|
@ -0,0 +1,178 @@
|
||||||
|
// Adafruit_ST7796S.cpp
|
||||||
|
//
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2025 Limor Fried/Ladyada for Adafruit Industries
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
#include "Adafruit_ST7796S.h"
|
||||||
|
|
||||||
|
static const uint8_t PROGMEM st7796s_init[] = {14, // 14 commands
|
||||||
|
ST77XX_SWRESET,
|
||||||
|
ST_CMD_DELAY, // Software reset
|
||||||
|
150,
|
||||||
|
0xF0,
|
||||||
|
1, // Unlock manufacturer
|
||||||
|
0xC3,
|
||||||
|
0xF0,
|
||||||
|
1,
|
||||||
|
0x96,
|
||||||
|
0xC5,
|
||||||
|
1, // VCOM Control
|
||||||
|
0x1C,
|
||||||
|
ST77XX_MADCTL,
|
||||||
|
1, // Memory Access
|
||||||
|
0x48,
|
||||||
|
ST77XX_COLMOD,
|
||||||
|
1, // Color Mode - 16 bit
|
||||||
|
0x55,
|
||||||
|
0xB0,
|
||||||
|
1, // Interface Control
|
||||||
|
0x80,
|
||||||
|
0xB4,
|
||||||
|
1, // Inversion Control
|
||||||
|
0x00,
|
||||||
|
0xB6,
|
||||||
|
3, // Display Function Control
|
||||||
|
0x80,
|
||||||
|
0x02,
|
||||||
|
0x3B,
|
||||||
|
0xB7,
|
||||||
|
1, // Entry Mode
|
||||||
|
0xC6,
|
||||||
|
0xF0,
|
||||||
|
1, // Lock manufacturer commands
|
||||||
|
0x69,
|
||||||
|
0xF0,
|
||||||
|
1,
|
||||||
|
0x3C,
|
||||||
|
ST77XX_SLPOUT,
|
||||||
|
ST_CMD_DELAY, // Exit sleep
|
||||||
|
150,
|
||||||
|
ST77XX_DISPON,
|
||||||
|
ST_CMD_DELAY, // Display on
|
||||||
|
150};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructor with software SPI.
|
||||||
|
* @param CS Chip select pin.
|
||||||
|
* @param RS Data/command pin.
|
||||||
|
* @param MOSI SPI MOSI pin.
|
||||||
|
* @param SCLK SPI clock pin.
|
||||||
|
* @param RST Reset pin (optional).
|
||||||
|
*/
|
||||||
|
Adafruit_ST7796S::Adafruit_ST7796S(int8_t CS, int8_t RS, int8_t MOSI,
|
||||||
|
int8_t SCLK, int8_t RST)
|
||||||
|
: Adafruit_ST77xx(ST7796S_TFTWIDTH, ST7796S_TFTHEIGHT, CS, RS, MOSI, SCLK,
|
||||||
|
RST) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructor with hardware SPI.
|
||||||
|
* @param CS Chip select pin.
|
||||||
|
* @param RS Data/command pin.
|
||||||
|
* @param RST Reset pin (optional).
|
||||||
|
*/
|
||||||
|
Adafruit_ST7796S::Adafruit_ST7796S(int8_t CS, int8_t RS, int8_t RST)
|
||||||
|
: Adafruit_ST77xx(ST7796S_TFTWIDTH, ST7796S_TFTHEIGHT, CS, RS, RST) {}
|
||||||
|
|
||||||
|
#if !defined(ESP8266)
|
||||||
|
/**
|
||||||
|
* @brief Constructor with hardware SPI and custom SPI class.
|
||||||
|
* @param spiClass Pointer to SPI class.
|
||||||
|
* @param CS Chip select pin.
|
||||||
|
* @param RS Data/command pin.
|
||||||
|
* @param RST Reset pin (optional).
|
||||||
|
*/
|
||||||
|
Adafruit_ST7796S::Adafruit_ST7796S(SPIClass *spiClass, int8_t CS, int8_t RS,
|
||||||
|
int8_t RST)
|
||||||
|
: Adafruit_ST77xx(ST7796S_TFTWIDTH, ST7796S_TFTHEIGHT, spiClass, CS, RS,
|
||||||
|
RST) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the display.
|
||||||
|
* @param width Display width in pixels.
|
||||||
|
* @param height Display height in pixels.
|
||||||
|
* @param rowOffset Row offset for display.
|
||||||
|
* @param colOffset Column offset for display.
|
||||||
|
* @param colorOrder Color order (RGB or BGR).
|
||||||
|
*/
|
||||||
|
void Adafruit_ST7796S::init(uint16_t width, uint16_t height, uint8_t rowOffset,
|
||||||
|
uint8_t colOffset, ST7796S_ColorOrder colorOrder) {
|
||||||
|
_width = width;
|
||||||
|
_height = height;
|
||||||
|
_rowstart = rowOffset;
|
||||||
|
_colstart = colOffset;
|
||||||
|
_colorOrder = colorOrder;
|
||||||
|
windowWidth = width;
|
||||||
|
windowHeight = height;
|
||||||
|
|
||||||
|
commonInit(NULL);
|
||||||
|
displayInit(st7796s_init);
|
||||||
|
invertOnCommand = ST77XX_INVOFF;
|
||||||
|
invertOffCommand = ST77XX_INVON;
|
||||||
|
invertDisplay(false);
|
||||||
|
setRotation(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the display rotation.
|
||||||
|
* @param m Rotation value (0-3).
|
||||||
|
*/
|
||||||
|
void Adafruit_ST7796S::setRotation(uint8_t m) {
|
||||||
|
uint8_t madctl = 0;
|
||||||
|
|
||||||
|
rotation = m & 3; // can't be higher than 3
|
||||||
|
|
||||||
|
switch (rotation) {
|
||||||
|
case 0:
|
||||||
|
madctl = ST77XX_MADCTL_MX | ST77XX_MADCTL_RGB | _colorOrder;
|
||||||
|
_xstart = _colstart;
|
||||||
|
_ystart = _rowstart;
|
||||||
|
_width = windowWidth;
|
||||||
|
_height = windowHeight;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
madctl = ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB | _colorOrder;
|
||||||
|
_xstart = _rowstart;
|
||||||
|
_ystart = _colstart;
|
||||||
|
_height = windowWidth;
|
||||||
|
_width = windowHeight;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
madctl = ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB | _colorOrder;
|
||||||
|
_xstart = _colstart;
|
||||||
|
_ystart = _rowstart;
|
||||||
|
_width = windowWidth;
|
||||||
|
_height = windowHeight;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
madctl = ST77XX_MADCTL_MY | ST77XX_MADCTL_MX | ST77XX_MADCTL_MV |
|
||||||
|
ST77XX_MADCTL_RGB | _colorOrder;
|
||||||
|
_xstart = _rowstart;
|
||||||
|
_ystart = _colstart;
|
||||||
|
_height = windowWidth;
|
||||||
|
_width = windowHeight;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println(madctl, HEX);
|
||||||
|
sendCommand(ST77XX_MADCTL, &madctl, 1);
|
||||||
|
}
|
||||||
74
Adafruit_ST7796S.h
Normal file
74
Adafruit_ST7796S.h
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
// Adafruit_ST7796S.h
|
||||||
|
//
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2025 Limor Fried/Ladyada for Adafruit Industries
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef _ADAFRUIT_ST7796S_H_
|
||||||
|
#define _ADAFRUIT_ST7796S_H_
|
||||||
|
|
||||||
|
#include "Adafruit_ST77xx.h"
|
||||||
|
|
||||||
|
#define ST7796S_TFTWIDTH 320
|
||||||
|
#define ST7796S_TFTHEIGHT 480
|
||||||
|
|
||||||
|
// ST7796S specific commands
|
||||||
|
#define ST7796S_RGBCTRL 0xB1
|
||||||
|
#define ST7796S_FRMCTR1 0xB2
|
||||||
|
#define ST7796S_PWCTRL1 0xC0
|
||||||
|
#define ST7796S_PWCTRL2 0xC1
|
||||||
|
#define ST7796S_VMCTRL1 0xC5
|
||||||
|
#define ST7796S_VMCTRL2 0xC7
|
||||||
|
#define ST7796S_PGAMCTRL 0xE0
|
||||||
|
#define ST7796S_NGAMCTRL 0xE1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enum for ST7796S color order.
|
||||||
|
*/
|
||||||
|
enum ST7796S_ColorOrder {
|
||||||
|
ST7796S_RGB = 0x00, ///< Red-Green-Blue color order
|
||||||
|
ST7796S_BGR = 0x08 ///< Blue-Green-Red color order
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adafruit driver for the ST7796S TFT display.
|
||||||
|
*/
|
||||||
|
class Adafruit_ST7796S : public Adafruit_ST77xx {
|
||||||
|
public:
|
||||||
|
Adafruit_ST7796S(int8_t CS, int8_t RS, int8_t MOSI, int8_t SCLK,
|
||||||
|
int8_t RST = -1);
|
||||||
|
Adafruit_ST7796S(int8_t CS, int8_t RS, int8_t RST = -1);
|
||||||
|
#if !defined(ESP8266)
|
||||||
|
Adafruit_ST7796S(SPIClass *spiClass, int8_t CS, int8_t RS, int8_t RST);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void init(uint16_t width = ST7796S_TFTWIDTH,
|
||||||
|
uint16_t height = ST7796S_TFTHEIGHT, uint8_t rowOffset = 0,
|
||||||
|
uint8_t colOffset = 0, ST7796S_ColorOrder colorOrder = ST7796S_RGB);
|
||||||
|
|
||||||
|
void setRotation(uint8_t r);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ST7796S_ColorOrder _colorOrder; ///< Color order setting.
|
||||||
|
uint16_t windowWidth, windowHeight; ///< Dimensions of the display window.
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
621
examples/ST7796S_demo/ST7796S_demo.ino
Normal file
621
examples/ST7796S_demo/ST7796S_demo.ino
Normal file
|
|
@ -0,0 +1,621 @@
|
||||||
|
// Basic full-color example for Adafruit_ST7796S
|
||||||
|
// Provides a 16-bit color video framebuffer to which Adafruit_GFX calls can be made.
|
||||||
|
|
||||||
|
#include <Adafruit_GFX.h>
|
||||||
|
#include <Adafruit_ST7796S.h>
|
||||||
|
#include <Fonts/FreeSansBold18pt7b.h> // A custom font
|
||||||
|
|
||||||
|
// Define display pin connections
|
||||||
|
#define TFT_CS 10
|
||||||
|
#define TFT_RST 9 // Or set to -1 and connect to Arduino RESET pin
|
||||||
|
#define TFT_DC 8
|
||||||
|
|
||||||
|
// Initialize the display
|
||||||
|
Adafruit_ST7796S display(TFT_CS, TFT_DC, TFT_RST);
|
||||||
|
|
||||||
|
#define PAUSE 1000 // Delay (milliseconds) between examples
|
||||||
|
uint8_t rotate = 0; // Current screen orientation (0-3)
|
||||||
|
#define CORNER_RADIUS 0
|
||||||
|
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("ST7796S graphics demo");
|
||||||
|
|
||||||
|
display.init(320, 480, 0, 0, ST7796S_RGB);
|
||||||
|
|
||||||
|
display.fillScreen(0); // Clear screen
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// Each of these functions demonstrates a different Adafruit_GFX concept:
|
||||||
|
show_shapes();
|
||||||
|
show_charts();
|
||||||
|
show_basic_text();
|
||||||
|
show_char_map();
|
||||||
|
show_custom_text();
|
||||||
|
show_bitmap();
|
||||||
|
|
||||||
|
#if !defined(__AVR__)
|
||||||
|
// we dont have the RAM or Flash for canvas
|
||||||
|
show_canvas();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (++rotate > 3) rotate = 0; // Cycle through screen rotations 0-3
|
||||||
|
display.setRotation(rotate); // Takes effect on next drawing command
|
||||||
|
}
|
||||||
|
|
||||||
|
// BASIC SHAPES EXAMPLE ----------------------------------------------------
|
||||||
|
|
||||||
|
void show_shapes() {
|
||||||
|
// Draw outlined and filled shapes. This demonstrates:
|
||||||
|
// - Enclosed shapes supported by GFX (points & lines are shown later).
|
||||||
|
// - Adapting to different-sized displays, and to rounded corners.
|
||||||
|
|
||||||
|
const int16_t cx = display.width() / 2; // Center of screen =
|
||||||
|
const int16_t cy = display.height() / 2; // half of width, height
|
||||||
|
int16_t minor = min(cx, cy); // Lesser of half width or height
|
||||||
|
// Shapes will be drawn in a square region centered on the screen. But one
|
||||||
|
// particular screen -- rounded 240x280 ST7789 -- has VERY rounded corners
|
||||||
|
// that would clip a couple of shapes if drawn full size. If using that
|
||||||
|
// screen type, reduce area by a few pixels to avoid drawing in corners.
|
||||||
|
if (CORNER_RADIUS > 40) minor -= 4;
|
||||||
|
const uint8_t pad = 5; // Space between shapes is 2X this
|
||||||
|
const int16_t size = minor - pad; // Shapes are this width & height
|
||||||
|
const int16_t half = size / 2; // 1/2 of shape size
|
||||||
|
|
||||||
|
display.fillScreen(0); // Start by clearing the screen; color 0 = black
|
||||||
|
|
||||||
|
// Draw outline version of basic shapes: rectangle, triangle, circle and
|
||||||
|
// rounded rectangle in different colors. Rather than hardcoded numbers
|
||||||
|
// for position and size, some arithmetic helps adapt to screen dimensions.
|
||||||
|
display.drawRect(cx - minor, cy - minor, size, size, 0xF800);
|
||||||
|
display.drawTriangle(cx + pad, cy - pad, cx + pad + half, cy - minor,
|
||||||
|
cx + minor - 1, cy - pad, 0x07E0);
|
||||||
|
display.drawCircle(cx - pad - half, cy + pad + half, half, 0x001F);
|
||||||
|
display.drawRoundRect(cx + pad, cy + pad, size, size, size / 5, 0xFFE0);
|
||||||
|
delay(PAUSE);
|
||||||
|
|
||||||
|
// Draw same shapes, same positions, but filled this time.
|
||||||
|
display.fillRect(cx - minor, cy - minor, size, size, 0xF800);
|
||||||
|
display.fillTriangle(cx + pad, cy - pad, cx + pad + half, cy - minor,
|
||||||
|
cx + minor - 1, cy - pad, 0x07E0);
|
||||||
|
display.fillCircle(cx - pad - half, cy + pad + half, half, 0x001F);
|
||||||
|
display.fillRoundRect(cx + pad, cy + pad, size, size, size / 5, 0xFFE0);
|
||||||
|
delay(PAUSE);
|
||||||
|
} // END SHAPE EXAMPLE
|
||||||
|
|
||||||
|
// CHART EXAMPLES ----------------------------------------------------------
|
||||||
|
|
||||||
|
void show_charts() {
|
||||||
|
// Draw some graphs and charts. GFX library doesn't handle these as native
|
||||||
|
// object types, but it only takes a little code to build them from simple
|
||||||
|
// shapes. This demonstrates:
|
||||||
|
// - Drawing points and horizontal, vertical and arbitrary lines.
|
||||||
|
// - Adapting to different-sized displays.
|
||||||
|
// - Graphics being clipped off edge.
|
||||||
|
// - Use of negative values to draw shapes "backward" from an anchor point.
|
||||||
|
// - C technique for finding array size at runtime (vs hardcoding).
|
||||||
|
|
||||||
|
display.fillScreen(0); // Clear screen
|
||||||
|
|
||||||
|
const int16_t cx = display.width() / 2; // Center of screen =
|
||||||
|
const int16_t cy = display.height() / 2; // half of width, height
|
||||||
|
const int16_t minor = min(cx, cy); // Lesser of half width or height
|
||||||
|
const int16_t major = max(cx, cy); // Greater of half width or height
|
||||||
|
|
||||||
|
// Let's start with a relatively simple sine wave graph with axes.
|
||||||
|
// Draw graph axes centered on screen. drawFastHLine() and drawFastVLine()
|
||||||
|
// need fewer arguments than normal 2-point line drawing shown later.
|
||||||
|
display.drawFastHLine(0, cy, display.width(), 0x0210); // Dark blue
|
||||||
|
display.drawFastVLine(cx, 0, display.height(), 0x0210);
|
||||||
|
|
||||||
|
// Then draw some tick marks along the axes. To keep this code simple,
|
||||||
|
// these aren't to any particular scale, but a real program may want that.
|
||||||
|
// The loop here draws them from the center outward and pays no mind
|
||||||
|
// whether the screen is rectangular; any ticks that go off-screen will
|
||||||
|
// be clipped by the library.
|
||||||
|
for (uint8_t i=1; i<=10; i++) {
|
||||||
|
// The Arduino map() function scales an input value (e.g. "i") from an
|
||||||
|
// input range (0-10 here) to an output range (0 to major-1 here).
|
||||||
|
// Very handy for making graphics adjust to different screens!
|
||||||
|
int16_t n = map(i, 0, 10, 0, major - 1); // Tick offset relative to center point
|
||||||
|
display.drawFastVLine(cx - n, cy - 5, 11, 0x210);
|
||||||
|
display.drawFastVLine(cx + n, cy - 5, 11, 0x210);
|
||||||
|
display.drawFastHLine(cx - 5, cy - n, 11, 0x210);
|
||||||
|
display.drawFastHLine(cx - 5, cy + n, 11, 0x210);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then draw sine wave over this using GFX drawPixel() function.
|
||||||
|
for (int16_t x=0; x<display.width(); x++) { // Each column of screen...
|
||||||
|
// Note the inverted Y axis here (cy-value rather than cy+value)
|
||||||
|
// because GFX, like most graphics libraries, has +Y heading down,
|
||||||
|
// vs. classic Cartesian coords which have +Y heading up.
|
||||||
|
int16_t y = cy - (int16_t)(sin((x - cx) * 0.05) * (float)minor * 0.5);
|
||||||
|
display.drawPixel(x, y, 0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(PAUSE);
|
||||||
|
|
||||||
|
// Next, let's draw some charts...
|
||||||
|
// NOTE: some other examples in this code take extra steps to avoid placing
|
||||||
|
// anything off in the rounded corners of certain displays. The charts do
|
||||||
|
// not. It's *possible* but would introduce a lot of complexity into code
|
||||||
|
// that's trying to show the basics. We'll leave the clipped charts here as
|
||||||
|
// a teachable moment: not all content suits all displays.
|
||||||
|
|
||||||
|
// A list of data to plot. These are Y values only; X assumed equidistant.
|
||||||
|
const uint8_t data[] = { 31, 42, 36, 58, 67, 88 }; // Percentages, 0-100
|
||||||
|
const uint8_t num_points = sizeof data / sizeof data[0]; // Length of data[] list
|
||||||
|
|
||||||
|
display.fillScreen(0); // Clear screen
|
||||||
|
display.setFont(); // Use default (built-in) font
|
||||||
|
display.setTextSize(2); // and 2X size for chart label
|
||||||
|
|
||||||
|
// Chart label is centered manually; 144 is the width in pixels of
|
||||||
|
// "Widget Sales" at 2X scale (12 chars * 6 px * 2 = 144). A later example
|
||||||
|
// shows automated centering based on string.
|
||||||
|
display.setCursor((display.width() - 144) / 2, 0);
|
||||||
|
display.print(F("Widget Sales")); // F("string") is in program memory, not RAM
|
||||||
|
// The chart-drawing code is then written to skip the top 20 rows where
|
||||||
|
// this label is located.
|
||||||
|
|
||||||
|
// First, a line chart, connecting the values point-to-point:
|
||||||
|
|
||||||
|
// Draw a grid of lines to provide scale & an interesting background.
|
||||||
|
for (uint8_t i=0; i<11; i++) {
|
||||||
|
int16_t x = map(i, 0, 10, 0, display.width() - 1); // Scale grid X to screen
|
||||||
|
display.drawFastVLine(x, 20, display.height(), 0x001F);
|
||||||
|
int16_t y = map(i, 0, 10, 20, display.height() - 1); // Scale grid Y to screen
|
||||||
|
display.drawFastHLine(0, y, display.width(), 0x001F);
|
||||||
|
}
|
||||||
|
// And then draw lines connecting data points. Load up the first point...
|
||||||
|
int16_t prev_x = 0;
|
||||||
|
int16_t prev_y = map(data[0], 0, 100, display.height() - 1, 20);
|
||||||
|
// Then connect lines to each subsequent point...
|
||||||
|
for (uint8_t i=1; i<num_points; i++) {
|
||||||
|
int16_t new_x = map(i, 0, num_points - 1, 0, display.width() - 1);
|
||||||
|
int16_t new_y = map(data[i], 0, 100, display.height() - 1, 20);
|
||||||
|
display.drawLine(prev_x, prev_y, new_x, new_y, 0x07FF);
|
||||||
|
prev_x = new_x;
|
||||||
|
prev_y = new_y;
|
||||||
|
}
|
||||||
|
// For visual interest, let's add a circle around each data point. This is
|
||||||
|
// done in a second pass so the circles are always drawn "on top" of lines.
|
||||||
|
for (uint8_t i=0; i<num_points; i++) {
|
||||||
|
int16_t x = map(i, 0, num_points - 1, 0, display.width() - 1);
|
||||||
|
int16_t y = map(data[i], 0, 100, display.height() - 1, 20);
|
||||||
|
display.drawCircle(x, y, 5, 0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(PAUSE);
|
||||||
|
|
||||||
|
// Then a bar chart of the same data...
|
||||||
|
|
||||||
|
// Erase the old chart but keep the label at top.
|
||||||
|
display.fillRect(0, 20, display.width(), display.height() - 20, 0);
|
||||||
|
|
||||||
|
// Just draw the Y axis lines; bar chart doesn't really need X lines.
|
||||||
|
for (uint8_t i=0; i<11; i++) {
|
||||||
|
int16_t y = map(i, 0, 10, 20, display.height() - 1);
|
||||||
|
display.drawFastHLine(0, y, display.width(), 0x001F);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bar_width = display.width() / num_points - 4; // 2px pad to either side
|
||||||
|
for (uint8_t i=0; i<num_points; i++) {
|
||||||
|
int16_t x = map(i, 0, num_points, 0, display.width()) + 2; // Left edge of bar
|
||||||
|
int16_t height = map(data[i], 0, 100, 0, display.height() - 20);
|
||||||
|
// Some GFX functions (rects, H/V lines and similar) can accept negative
|
||||||
|
// width/height values. What this does is anchor the shape at the right or
|
||||||
|
// bottom coordinate (rather than the usual left/top) and draw back from
|
||||||
|
// there, hence the -height here (bar is anchored at bottom of screen):
|
||||||
|
display.fillRect(x, display.height() - 1, bar_width, -height, 0xFFE0);
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(PAUSE);
|
||||||
|
|
||||||
|
} // END CHART EXAMPLES
|
||||||
|
|
||||||
|
// TEXT ALIGN FUNCTIONS ----------------------------------------------------
|
||||||
|
|
||||||
|
// Adafruit_GFX only handles left-aligned text. This is normal and by design;
|
||||||
|
// it's a rare need that would further strain AVR by incurring a ton of extra
|
||||||
|
// code to properly handle, and some details would confuse. If needed, these
|
||||||
|
// functions give a fair approximation, with the "gotchas" that multi-line
|
||||||
|
// input won't work, and this operates only as a println(), not print()
|
||||||
|
// (though, unlike println(), cursor X does not reset to column 0, instead
|
||||||
|
// returning to initial column and downward by font's line spacing). If you
|
||||||
|
// can work with those constraints, it's a modest amount of code to copy
|
||||||
|
// into a project. Or, if your project only needs one or two aligned strings,
|
||||||
|
// simply use getTextBounds() for a bounding box and work from there.
|
||||||
|
// DO NOT ATTEMPT TO MAKE THIS A GFX-NATIVE FEATURE, EVERYTHING WILL BREAK.
|
||||||
|
|
||||||
|
typedef enum { // Alignment options passed to functions below
|
||||||
|
GFX_ALIGN_LEFT,
|
||||||
|
GFX_ALIGN_CENTER,
|
||||||
|
GFX_ALIGN_RIGHT
|
||||||
|
} GFXalign;
|
||||||
|
|
||||||
|
// Draw text aligned relative to current cursor position. Arguments:
|
||||||
|
// gfx : An Adafruit_GFX-derived type (e.g. display or canvas object).
|
||||||
|
// str : String to print (as a char *).
|
||||||
|
// align : One of the GFXalign values declared above.
|
||||||
|
// GFX_ALIGN_LEFT is normal left-aligned println() behavior.
|
||||||
|
// GFX_ALIGN_CENTER prints centered on cursor pos.
|
||||||
|
// GFX_ALIGN_RIGHT prints right-aligned to cursor pos.
|
||||||
|
// Cursor advances down one line a la println(). Column is unchanged.
|
||||||
|
void print_aligned(Adafruit_GFX &gfx, const char *str,
|
||||||
|
GFXalign align = GFX_ALIGN_LEFT) {
|
||||||
|
uint16_t w, h;
|
||||||
|
int16_t x, y, cursor_x, cursor_x_save;
|
||||||
|
cursor_x = cursor_x_save = gfx.getCursorX();
|
||||||
|
gfx.getTextBounds(str, 0, gfx.getCursorY(), &x, &y, &w, &h);
|
||||||
|
if (align == GFX_ALIGN_RIGHT) cursor_x -= w;
|
||||||
|
else if (align == GFX_ALIGN_CENTER) cursor_x -= w / 2;
|
||||||
|
//gfx.drawRect(cursor_x, y, w, h, 0xF800); // Debug rect
|
||||||
|
gfx.setCursor(cursor_x - x, gfx.getCursorY()); // Center/right align
|
||||||
|
gfx.println(str);
|
||||||
|
gfx.setCursor(cursor_x_save, gfx.getCursorY()); // Restore cursor X
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equivalent function for strings in flash memory (e.g. F("Foo")). Body
|
||||||
|
// appears identical to above function, but with C++ overloading it it works
|
||||||
|
// from flash instead of RAM. Any changes should be made in both places.
|
||||||
|
void print_aligned(Adafruit_GFX &gfx, const __FlashStringHelper *str,
|
||||||
|
GFXalign align = GFX_ALIGN_LEFT) {
|
||||||
|
uint16_t w, h;
|
||||||
|
int16_t x, y, cursor_x, cursor_x_save;
|
||||||
|
cursor_x = cursor_x_save = gfx.getCursorX();
|
||||||
|
gfx.getTextBounds(str, 0, gfx.getCursorY(), &x, &y, &w, &h);
|
||||||
|
if (align == GFX_ALIGN_RIGHT) cursor_x -= w;
|
||||||
|
else if (align == GFX_ALIGN_CENTER) cursor_x -= w / 2;
|
||||||
|
//gfx.drawRect(cursor_x, y, w, h, 0xF800); // Debug rect
|
||||||
|
gfx.setCursor(cursor_x - x, gfx.getCursorY()); // Center/right align
|
||||||
|
gfx.println(str);
|
||||||
|
gfx.setCursor(cursor_x_save, gfx.getCursorY()); // Restore cursor X
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equivalent function for Arduino Strings; converts to C string (char *)
|
||||||
|
// and calls corresponding print_aligned() implementation.
|
||||||
|
void print_aligned(Adafruit_GFX &gfx, const String &str,
|
||||||
|
GFXalign align = GFX_ALIGN_LEFT) {
|
||||||
|
print_aligned(gfx, const_cast<char *>(str.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEXT EXAMPLES -----------------------------------------------------------
|
||||||
|
|
||||||
|
// This section demonstrates:
|
||||||
|
// - Using the default 5x7 built-in font, including scaling in each axis.
|
||||||
|
// - How to access all characters of this font, including symbols.
|
||||||
|
// - Using a custom font, including alignment techniques that aren't a normal
|
||||||
|
// part of the GFX library (uses functions above).
|
||||||
|
|
||||||
|
void show_basic_text() {
|
||||||
|
// Show text scaling with built-in font.
|
||||||
|
display.fillScreen(0);
|
||||||
|
display.setFont(); // Use default font
|
||||||
|
display.setCursor(0, CORNER_RADIUS); // Initial cursor position
|
||||||
|
display.setTextSize(1); // Default size
|
||||||
|
display.println(F("Standard built-in font"));
|
||||||
|
display.setTextSize(2);
|
||||||
|
display.println(F("BIG TEXT"));
|
||||||
|
display.setTextSize(3);
|
||||||
|
// "BIGGER TEXT" won't fit on narrow screens, so abbreviate there.
|
||||||
|
display.println((display.width() >= 200) ? F("BIGGER TEXT") : F("BIGGER"));
|
||||||
|
display.setTextSize(2, 4);
|
||||||
|
display.println(F("TALL and"));
|
||||||
|
display.setTextSize(4, 2);
|
||||||
|
display.println(F("WIDE"));
|
||||||
|
|
||||||
|
delay(PAUSE);
|
||||||
|
} // END BASIC TEXT EXAMPLE
|
||||||
|
|
||||||
|
void show_char_map() {
|
||||||
|
// "Code Page 437" is a name given to the original IBM PC character set.
|
||||||
|
// Despite age and limited language support, still seen in small embedded
|
||||||
|
// settings as it has some useful symbols and accented characters. The
|
||||||
|
// default 5x7 pixel font of Adafruit_GFX is modeled after CP437. This
|
||||||
|
// function draws a table of all the characters & explains some issues.
|
||||||
|
|
||||||
|
// There are 256 characters in all. Draw table as 16 rows of 16 columns,
|
||||||
|
// plus hexadecimal row & column labels. How big can each cell be drawn?
|
||||||
|
const int cell_size = min(display.width(), display.height()) / 17;
|
||||||
|
if (cell_size < 8) return; // Screen is too small for table, skip example.
|
||||||
|
const int total_size = cell_size * 17; // 16 cells + 1 row or column label
|
||||||
|
|
||||||
|
// Set up for default 5x7 font at 1:1 scale. Custom fonts are NOT used
|
||||||
|
// here as most are only 128 characters to save space (the "7b" at the
|
||||||
|
// end of many GFX font names means "7 bits," i.e. 128 characters).
|
||||||
|
display.setFont();
|
||||||
|
display.setTextSize(1);
|
||||||
|
|
||||||
|
// Early Adafruit_GFX was missing one symbol, throwing off some indices!
|
||||||
|
// But fixing the library would break MANY existing sketches that relied
|
||||||
|
// on the degrees symbol and others. The default behavior is thus "broken"
|
||||||
|
// to keep older code working. New code can access the CORRECT full CP437
|
||||||
|
// table by calling this function like so:
|
||||||
|
display.cp437(true);
|
||||||
|
|
||||||
|
display.fillScreen(0);
|
||||||
|
|
||||||
|
const int16_t x = (display.width() - total_size) / 2; // Upper left corner of
|
||||||
|
int16_t y = (display.height() - total_size) / 2; // table centered on screen
|
||||||
|
if (y >= 4) { // If there's a little extra space above & below, scoot table
|
||||||
|
y += 4; // down a few pixels and show a message centered at top.
|
||||||
|
display.setCursor((display.width() - 114) / 2, 0); // 114 = pixel width
|
||||||
|
display.print(F("CP437 Character Map")); // of this message
|
||||||
|
}
|
||||||
|
|
||||||
|
const int16_t inset_x = (cell_size - 5) / 2; // To center each character within cell,
|
||||||
|
const int16_t inset_y = (cell_size - 8) / 2; // compute X & Y offset from corner.
|
||||||
|
|
||||||
|
for (uint8_t row=0; row<16; row++) { // 16 down...
|
||||||
|
// Draw row and columm headings as hexadecimal single digits. To get the
|
||||||
|
// hex value for a specific character, combine the left & top labels,
|
||||||
|
// e.g. Pi symbol is row E, column 3, thus: display.print((char)0xE3);
|
||||||
|
display.setCursor(x + (row + 1) * cell_size + inset_x, y + inset_y);
|
||||||
|
display.print(row, HEX); // This actually draws column labels
|
||||||
|
display.setCursor(x + inset_x, y + (row + 1) * cell_size + inset_y);
|
||||||
|
display.print(row, HEX); // and THIS is the row labels
|
||||||
|
for (uint8_t col=0; col<16; col++) { // 16 across...
|
||||||
|
if ((row + col) & 1) { // Fill alternating cells w/gray
|
||||||
|
display.fillRect(x + (col + 1) * cell_size, y + (row + 1) * cell_size,
|
||||||
|
cell_size, cell_size, 0x630C);
|
||||||
|
}
|
||||||
|
// drawChar() bypasses usual cursor positioning to go direct to an X/Y
|
||||||
|
// location. If foreground & background match, it's drawn transparent.
|
||||||
|
display.drawChar(x + (col + 1) * cell_size + inset_x,
|
||||||
|
y + (row + 1) * cell_size + inset_y, row * 16 + col,
|
||||||
|
0xFFFF, 0xFFFF, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(PAUSE * 2);
|
||||||
|
} // END CHAR MAP EXAMPLE
|
||||||
|
|
||||||
|
void show_custom_text() {
|
||||||
|
// Show use of custom fonts, plus how to do center or right alignment
|
||||||
|
// using some additional functions provided earlier.
|
||||||
|
|
||||||
|
display.fillScreen(0);
|
||||||
|
display.setFont(&FreeSansBold18pt7b);
|
||||||
|
display.setTextSize(1);
|
||||||
|
display.setTextWrap(false); // Allow text off edges
|
||||||
|
|
||||||
|
// Get "M height" of custom font and move initial base line there:
|
||||||
|
uint16_t w, h;
|
||||||
|
int16_t x, y;
|
||||||
|
display.getTextBounds("M", 0, 0, &x, &y, &w, &h);
|
||||||
|
// On rounded 240x280 display in tall orientation, "Custom Font" gets
|
||||||
|
// clipped by top corners. Scoot text down a few pixels in that one case.
|
||||||
|
if (CORNER_RADIUS && (display.height() == 280)) h += 20;
|
||||||
|
display.setCursor(display.width() / 2, h);
|
||||||
|
|
||||||
|
if (display.width() >= 200) {
|
||||||
|
print_aligned(display, F("Custom Font"), GFX_ALIGN_CENTER);
|
||||||
|
display.setCursor(0, display.getCursorY() + 10);
|
||||||
|
print_aligned(display, F("Align Left"), GFX_ALIGN_LEFT);
|
||||||
|
display.setCursor(display.width() / 2, display.getCursorY());
|
||||||
|
print_aligned(display, F("Centered"), GFX_ALIGN_CENTER);
|
||||||
|
// Small rounded screen, when oriented the wide way, "Right" gets
|
||||||
|
// clipped by bottom right corner. Scoot left to compensate.
|
||||||
|
int16_t x_offset = (CORNER_RADIUS && (display.height() < 200)) ? 15 : 0;
|
||||||
|
display.setCursor(display.width() - x_offset, display.getCursorY());
|
||||||
|
print_aligned(display, F("Align Right"), GFX_ALIGN_RIGHT);
|
||||||
|
} else {
|
||||||
|
// On narrow screens, use abbreviated messages
|
||||||
|
print_aligned(display, F("Font &"), GFX_ALIGN_CENTER);
|
||||||
|
print_aligned(display, F("Align"), GFX_ALIGN_CENTER);
|
||||||
|
display.setCursor(0, display.getCursorY() + 10);
|
||||||
|
print_aligned(display, F("Left"), GFX_ALIGN_LEFT);
|
||||||
|
display.setCursor(display.width() / 2, display.getCursorY());
|
||||||
|
print_aligned(display, F("Center"), GFX_ALIGN_CENTER);
|
||||||
|
display.setCursor(display.width(), display.getCursorY());
|
||||||
|
print_aligned(display, F("Right"), GFX_ALIGN_RIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(PAUSE);
|
||||||
|
} // END CUSTOM FONT EXAMPLE
|
||||||
|
|
||||||
|
// BITMAP EXAMPLE ----------------------------------------------------------
|
||||||
|
|
||||||
|
// This section demonstrates:
|
||||||
|
// - Embedding a small bitmap in the code (flash memory).
|
||||||
|
// - Drawing that bitmap in various colors, and transparently (only '1' bits
|
||||||
|
// are drawn; '0' bits are skipped, leaving screen contents in place).
|
||||||
|
// - Use of the color565() function to decimate 24-bit RGB to 16 bits.
|
||||||
|
|
||||||
|
#define HEX_WIDTH 16 // Bitmap width in pixels
|
||||||
|
#define HEX_HEIGHT 16 // Bitmap height in pixels
|
||||||
|
// Bitmap data. PROGMEM ensures it's in flash memory (not RAM). And while
|
||||||
|
// it would be valid to leave the brackets empty here (i.e. hex_bitmap[]),
|
||||||
|
// having dimensions with a little math makes the compiler verify the
|
||||||
|
// correct number of bytes are present in the list.
|
||||||
|
PROGMEM const uint8_t hex_bitmap[(HEX_WIDTH + 7) / 8 * HEX_HEIGHT] = {
|
||||||
|
0b00000001, 0b10000000,
|
||||||
|
0b00000111, 0b11100000,
|
||||||
|
0b00011111, 0b11111000,
|
||||||
|
0b01111111, 0b11111110,
|
||||||
|
0b01111111, 0b11111110,
|
||||||
|
0b01111111, 0b11111110,
|
||||||
|
0b01111111, 0b11111110,
|
||||||
|
0b01111111, 0b11111110,
|
||||||
|
0b01111111, 0b11111110,
|
||||||
|
0b01111111, 0b11111110,
|
||||||
|
0b01111111, 0b11111110,
|
||||||
|
0b01111111, 0b11111110,
|
||||||
|
0b01111111, 0b11111110,
|
||||||
|
0b00011111, 0b11111000,
|
||||||
|
0b00000111, 0b11100000,
|
||||||
|
0b00000001, 0b10000000,
|
||||||
|
};
|
||||||
|
#define Y_SPACING (HEX_HEIGHT - 2) // Used by code below for positioning
|
||||||
|
|
||||||
|
void show_bitmap() {
|
||||||
|
display.fillScreen(0);
|
||||||
|
|
||||||
|
// Not screen center, but UL coordinates of center hexagon bitmap
|
||||||
|
const int16_t center_x = (display.width() - HEX_WIDTH) / 2;
|
||||||
|
const int16_t center_y = (display.height() - HEX_HEIGHT) / 2;
|
||||||
|
const uint8_t steps = min((display.height() - HEX_HEIGHT) / Y_SPACING,
|
||||||
|
display.width() / HEX_WIDTH - 1) / 2;
|
||||||
|
|
||||||
|
display.drawBitmap(center_x, center_y, hex_bitmap, HEX_WIDTH, HEX_HEIGHT,
|
||||||
|
0xFFFF); // Draw center hexagon in white
|
||||||
|
|
||||||
|
// Tile the hexagon bitmap repeatedly in a range of hues. Don't mind the
|
||||||
|
// bit of repetition in the math, the optimizer easily picks this up.
|
||||||
|
// Also, if math looks odd, keep in mind "PEMDAS" operator precedence;
|
||||||
|
// multiplication and division occur before addition and subtraction.
|
||||||
|
for (uint8_t a=0; a<=steps; a++) {
|
||||||
|
for (uint8_t b=1; b<=steps; b++) {
|
||||||
|
display.drawBitmap( // Right section centered red: a = green, b = blue
|
||||||
|
center_x + (a + b) * HEX_WIDTH / 2,
|
||||||
|
center_y + (a - b) * Y_SPACING,
|
||||||
|
hex_bitmap, HEX_WIDTH, HEX_HEIGHT,
|
||||||
|
display.color565(255, 255 - 255 * a / steps, 255 - 255 * b / steps));
|
||||||
|
display.drawBitmap( // UL section centered green: a = blue, b = red
|
||||||
|
center_x - b * HEX_WIDTH + a * HEX_WIDTH / 2,
|
||||||
|
center_y - a * Y_SPACING,
|
||||||
|
hex_bitmap, HEX_WIDTH, HEX_HEIGHT,
|
||||||
|
display.color565(255 - 255 * b / steps, 255, 255 - 255 * a / steps));
|
||||||
|
display.drawBitmap( // LL section centered blue: a = red, b = green
|
||||||
|
center_x - a * HEX_WIDTH + b * HEX_WIDTH / 2,
|
||||||
|
center_y + b * Y_SPACING,
|
||||||
|
hex_bitmap, HEX_WIDTH, HEX_HEIGHT,
|
||||||
|
display.color565(255 - 255 * a / steps, 255 - 255 * b / steps, 255));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(PAUSE);
|
||||||
|
} // END BITMAP EXAMPLE
|
||||||
|
|
||||||
|
// CANVAS EXAMPLE ----------------------------------------------------------
|
||||||
|
|
||||||
|
// This section demonstrates:
|
||||||
|
// - How to refresh changing values onscreen without erase/redraw flicker.
|
||||||
|
// - Using an offscreen canvas. It's similar to a bitmap above, but rather
|
||||||
|
// than a fixed pattern in flash memory, it's drawable like the screen.
|
||||||
|
// - More tips on text alignment, and adapting to different screen sizes.
|
||||||
|
|
||||||
|
#define PADDING 6 // Pixels between axis label and value
|
||||||
|
|
||||||
|
void show_canvas() {
|
||||||
|
// For this example, let's suppose we want to display live readings from a
|
||||||
|
// sensor such as a three-axis accelerometer, something like:
|
||||||
|
// X: (number)
|
||||||
|
// Y: (number)
|
||||||
|
// Z: (number)
|
||||||
|
// To look extra classy, we want a custom font, and the labels for each
|
||||||
|
// axis are right-aligned so the ':' characters line up...
|
||||||
|
|
||||||
|
display.setFont(&FreeSansBold18pt7b); // Use a custom font
|
||||||
|
display.setTextSize(1); // and reset to 1:1 scale
|
||||||
|
|
||||||
|
char *label[] = { "X:", "Y:", "Z:" }; // Labels for each axis
|
||||||
|
const uint16_t color[] = { 0xF800, 0x07E0, 0x001F }; // Colors for each value
|
||||||
|
|
||||||
|
// To get the labels right-aligned, one option would be simple trial and
|
||||||
|
// error to find a column that looks good and doesn't clip anything off.
|
||||||
|
// Let's do this dynamically though, so it adapts to any font or labels!
|
||||||
|
// Start by finding the widest of the label strings:
|
||||||
|
uint16_t w, h, max_w = 0;
|
||||||
|
int16_t x, y;
|
||||||
|
for (uint8_t i=0; i<3; i++) { // For each label...
|
||||||
|
display.getTextBounds(label[i], 0, 0, &x, &y, &w, &h);
|
||||||
|
if (w > max_w) max_w = w; // Keep track of widest label
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rounded corners throwing us a curve again. If needed, scoot everything
|
||||||
|
// to the right a bit on wide displays, down a bit on tall ones.
|
||||||
|
int16_t y_offset = 0;
|
||||||
|
if (display.width() > display.height()) max_w += CORNER_RADIUS;
|
||||||
|
else y_offset = CORNER_RADIUS;
|
||||||
|
|
||||||
|
// Now we have max_w for right-aligning the labels. Before we draw them
|
||||||
|
// though...in order to perform flicker-free updates, the numbers we show
|
||||||
|
// will be rendered in either a GFXcanvas1 or GFXcanvas16 object; a 1-bit
|
||||||
|
// or 16-bit offscreen bitmap, RAM permitting. The correct size for this
|
||||||
|
// canvas could also be trial-and-errored, but again let's make this adapt
|
||||||
|
// automatically. The width of the canvas will span from max_w (plus a few
|
||||||
|
// pixels for padding) to the right edge. But the height? Looking at an
|
||||||
|
// uppercase 'M' can work in many situations, but some fonts have ascenders
|
||||||
|
// and descenders on digits, and in some locales a comma (extending below
|
||||||
|
// the baseline) is the decimal separator. Feed ALL the numeric chars into
|
||||||
|
// getTextBounds() for a cumulative height:
|
||||||
|
display.setTextWrap(false); // Keep on one line
|
||||||
|
display.getTextBounds(F("0123456789.,-"), 0, 0, &x, &y, &w, &h);
|
||||||
|
|
||||||
|
// Now declare a GFXcanvas16 object based on the computed width & height:
|
||||||
|
GFXcanvas16 canvas16(display.width() - max_w - PADDING, h);
|
||||||
|
|
||||||
|
// Small devices (e.g. ATmega328p) will almost certainly lack enough RAM
|
||||||
|
// for the canvas. Check if canvas buffer exists. If not, fall back on
|
||||||
|
// using a 1-bit (rather than 16-bit) canvas. Much more RAM friendly, but
|
||||||
|
// not as fast to draw. If a project doesn't require super interactive
|
||||||
|
// updates, consider just going straight for the more compact Canvas1.
|
||||||
|
if (canvas16.getBuffer()) {
|
||||||
|
// If here, 16-bit canvas allocated successfully! Point of interest,
|
||||||
|
// only one canvas is needed for this example, we can reuse it for all
|
||||||
|
// three numbers because the regions are the same size.
|
||||||
|
|
||||||
|
// display and canvas are independent drawable objects; must explicitly
|
||||||
|
// set the same custom font to use on the canvas now:
|
||||||
|
canvas16.setFont(&FreeSansBold18pt7b);
|
||||||
|
|
||||||
|
// Clear display and print labels. Once drawn, these remain untouched.
|
||||||
|
display.fillScreen(0);
|
||||||
|
display.setCursor(max_w, -y + y_offset); // Set baseline for first row
|
||||||
|
for (uint8_t i=0; i<3; i++) print_aligned(display, label[i], GFX_ALIGN_RIGHT);
|
||||||
|
|
||||||
|
// Last part now is to print numbers on the canvas and copy the canvas to
|
||||||
|
// the display, repeating for several seconds...
|
||||||
|
uint32_t elapsed, startTime = millis();
|
||||||
|
while ((elapsed = (millis() - startTime)) <= PAUSE * 2) {
|
||||||
|
for (uint8_t i=0; i<3; i++) { // For each label...
|
||||||
|
canvas16.fillScreen(0); // fillScreen() in this case clears canvas
|
||||||
|
canvas16.setCursor(0, -y); // Reset baseline for custom font
|
||||||
|
canvas16.setTextColor(color[i]);
|
||||||
|
// These aren't real accelerometer readings, just cool-looking numbers.
|
||||||
|
// Notice we print to the canvas, NOT the display:
|
||||||
|
canvas16.print(sin(elapsed / 200.0 + (float)i * M_PI * 2.0 / 3.0), 5);
|
||||||
|
// And HERE is the secret sauce to flicker-free updates. Canvas details
|
||||||
|
// can be passed to the drawRGBBitmap() function, which fully overwrites
|
||||||
|
// prior screen contents in that area. yAdvance is font line spacing.
|
||||||
|
display.drawRGBBitmap(max_w + PADDING, i * FreeSansBold18pt7b.yAdvance +
|
||||||
|
y_offset, canvas16.getBuffer(), canvas16.width(),
|
||||||
|
canvas16.height());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Insufficient RAM for Canvas16. Try declaring a 1-bit canvas instead...
|
||||||
|
GFXcanvas1 canvas1(display.width() - max_w - PADDING, h);
|
||||||
|
// If even this smaller object fails, can't proceed, cancel this example.
|
||||||
|
if (!canvas1.getBuffer()) return;
|
||||||
|
|
||||||
|
// Remainder here is nearly identical to the code above, simply using a
|
||||||
|
// different canvas type. It's stripped of most comments for brevity.
|
||||||
|
canvas1.setFont(&FreeSansBold18pt7b);
|
||||||
|
display.fillScreen(0);
|
||||||
|
display.setCursor(max_w, -y + y_offset);
|
||||||
|
for (uint8_t i=0; i<3; i++) print_aligned(display, label[i], GFX_ALIGN_RIGHT);
|
||||||
|
uint32_t elapsed, startTime = millis();
|
||||||
|
while ((elapsed = (millis() - startTime)) <= PAUSE * 2) {
|
||||||
|
for (uint8_t i=0; i<3; i++) {
|
||||||
|
canvas1.fillScreen(0);
|
||||||
|
canvas1.setCursor(0, -y);
|
||||||
|
canvas1.print(sin(elapsed / 200.0 + (float)i * M_PI * 2.0 / 3.0), 5);
|
||||||
|
// Here's the secret sauce to flicker-free updates with GFXcanvas1.
|
||||||
|
// Canvas details can be passed to the drawBitmap() function, and by
|
||||||
|
// specifying both a foreground AND BACKGROUND color (0), this will fully
|
||||||
|
// overwrite/erase prior screen contents in that area (vs transparent).
|
||||||
|
display.drawBitmap(max_w + PADDING, i * FreeSansBold18pt7b.yAdvance +
|
||||||
|
y_offset, canvas1.getBuffer(), canvas1.width(),
|
||||||
|
canvas1.height(), color[i], 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Because canvas object was declared locally to this function, it's freed
|
||||||
|
// automatically when the function returns; no explicit delete needed.
|
||||||
|
} // END CANVAS EXAMPLE
|
||||||
|
|
@ -2,8 +2,8 @@ name=Adafruit ST7735 and ST7789 Library
|
||||||
version=1.10.4
|
version=1.10.4
|
||||||
author=Adafruit
|
author=Adafruit
|
||||||
maintainer=Adafruit <info@adafruit.com>
|
maintainer=Adafruit <info@adafruit.com>
|
||||||
sentence=This is a library for the Adafruit ST7735 and ST7789 SPI displays.
|
sentence=This is a library for the Adafruit ST7735, ST7789, ST7796S SPI displays.
|
||||||
paragraph=This is a library for the Adafruit ST7735 and ST7789 SPI displays.
|
paragraph=This is a library for the Adafruit ST7735, ST7789, ST7796S SPI displays.
|
||||||
category=Display
|
category=Display
|
||||||
url=https://github.com/adafruit/Adafruit-ST7735-Library
|
url=https://github.com/adafruit/Adafruit-ST7735-Library
|
||||||
architectures=*
|
architectures=*
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue