Hardware components | ||||||
| × | 1 | ||||
| × | 1 |
For many projects a small TFT display is fully sufficient. The ARDUINO IDE supports 1.8" TFT displays like this:
And inside the Arduino IDE menu you will find --> File --> Examples --> Retired --> TFT that works pretty well with Arduino UNO R3 (and many others). When I tried to use it with the new UNO R4 I got this error message
C:\Program Files (x86)\Arduino\libraries\TFT\src\utility\glcdfont.c:3:10: fatal error: avr/io.h: No such file or directory
#include <avr/io.h>^~~~~~~~~~compilation terminated.As I did not find a solution or a work-around on the web, I managed to find some source that supported the display without using any library:
Unfortunately, the author was using direct port access which obviously cannot work with the Arduino R4 and had to be replaced by pinMode and digitalWrite statements.
After modifying the code published by Bruce E. Hall in 2014, exactly the same code was working with both the Arduino UNO R3 and R4 as well. As the UNO R4 runs with triple speed and is using 32 bit registers you might expect it runs 3*4=12 times faster. But it was disappointing:
I replaced the print statement of "Hello world" by printing time and __VERSION__ values. The R4 performes 2.6 times slower than the R3. Really disappointing!
Actually, the performace depends on what operations have to be executed. My results are confirmed by fast16lib, the author of the famous SdFat library, saying: "I did some performance tests. The results were very disappointing. I hoped the R4 would perform better than the R3 since it has a max SPI clock rate of 24 MHz vs 8 MHz for the R3." (Source: https://forum.arduino.cc/t/uno-r4-poor-spi-performance/1143935).
Have a look at a simple bubble sort:
// TEST ROUTINES
const int N = 390;
char a[N];
// Writes 420 characters (5x7) to screen in portrait mode
void sortChars() {
for (int i = 0; i < N; i++) a[i] = 'A' + random(26);
printAll();
long t1 = millis();
// bubble sort:
for (int i = 0; i < N - 1; i++)
for (int j = i + 1; j < N; j++)
if (a[i] > a[j]) {
char b = a[i];
a[i] = a[j];
a[j] = b;
}
long t2 = millis();
printAll();
WriteString(" t=", WHITE);
WriteInt(t2 - t1);
WriteString("ms", WHITE);
}
Results are 69 ms for the R3 compared to only 17 ms for the R4, that is more than four times better. So, internal operations can be performed much faster.
TFT18_R4
ArduinoNo preview (download only).
AVRTFT_r4.ino
Arduino/*
-----------------------------------------------------------------------------
TFT: Experiments interfacing ATmega328 to an ST7735 1.8" LCD TFT display
schreibt Zeichensatz, LineTest, Elipse, Text
Author : Bruce E. Hall <bhall66@gmail.com>
Website : w8bh.net
Version : 1.0
Date : 04 May 2014
Target : ATmega328P microcontroller
Language : C, using AVR studio 6
Size : 3622 bytes
Fuse settings: 8 MHz osc with 65 ms Delay, SPI enable; *NO* clock/8
Connections from LCD to DC Boarduino:
TFT Arduino
1 (backlight) +5V
2 (MISO) n/c
3 13 (SCK) digital13, PB5(SCK)
4 11 (MOSI) digital11, PB3(MOSI)
5 GND (TFT_Select) gnd
7 9 (DC) digital9, PB1
8 8 (Reset) digital8, PB0
9 Vcc (Vcc) +5V
10 GND (gnd) gnd
see: w8bh.net/avr/AvrTFT.pdf
checked 16.11.22: o.k.
Vergleich R3: 5925 ms, R4 9248 ms
*/
const byte RESET = 8;
const byte DC = 9;
const byte ChipSelect = 10;
#include <SPI.h>
// Color constants
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x0400
#define LIME 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
void setup() {
SetupPorts(); // use PortB for LCD interface
OpenSPI(); // start communication to TFT
InitDisplay(); // initialize TFT controller
long t1 = millis();
ClearScreen(); // takes 72 milliseconds
SetOrientation(180);
DrawRect(10, 20, 30, 80, 0xff00);
FillRect(12, 22, 20, 60, 0x0ff0);
DrawRect(61, 77, 63, 79, 0xffff);
long t2 = millis();
Serial.begin(9600);
Serial.println(t2 - t1);
PortraitChars(); // show full screen of ASCII chars
LineTest(); // paint background of lines
FillEllipse(60, 75, 100, 50, BLACK); // erase an oval in center
Ellipse(60, 75, 100, 50, LIME); // outline the oval in green
long t3 = millis();
char str[10];
ltoa(t3 - t2, str, 10);
// char *str = "Hello, World!"; // text to display
GotoXY(4, 7); // position text cursor
WriteString(str, YELLOW); // display text inside oval
WriteString(" ms",YELLOW);
GotoXY(4, 8);
WriteString("VER " __VERSION__, GREEN);
CloseSPI(); // close communication with TFT
Serial.println(t3 - t2);
}
void loop() {}
// ---------------------------------------------------------------------------
// GLOBAL VARIABLES
const byte FONT_CHARS[96][5] PROGMEM = {
{ 0x00, 0x00, 0x00, 0x00, 0x00 }, // (space)
{ 0x00, 0x00, 0x5F, 0x00, 0x00 }, // !
{ 0x00, 0x07, 0x00, 0x07, 0x00 }, // "
{ 0x14, 0x7F, 0x14, 0x7F, 0x14 }, // #
{ 0x24, 0x2A, 0x7F, 0x2A, 0x12 }, // $
{ 0x23, 0x13, 0x08, 0x64, 0x62 }, // %
{ 0x36, 0x49, 0x55, 0x22, 0x50 }, // &
{ 0x00, 0x05, 0x03, 0x00, 0x00 }, // '
{ 0x00, 0x1C, 0x22, 0x41, 0x00 }, // (
{ 0x00, 0x41, 0x22, 0x1C, 0x00 }, // )
{ 0x08, 0x2A, 0x1C, 0x2A, 0x08 }, // *
{ 0x08, 0x08, 0x3E, 0x08, 0x08 }, // +
{ 0x00, 0x50, 0x30, 0x00, 0x00 }, // ,
{ 0x08, 0x08, 0x08, 0x08, 0x08 }, // -
{ 0x00, 0x60, 0x60, 0x00, 0x00 }, // .
{ 0x20, 0x10, 0x08, 0x04, 0x02 }, // /
{ 0x3E, 0x51, 0x49, 0x45, 0x3E }, // 0
{ 0x00, 0x42, 0x7F, 0x40, 0x00 }, // 1
{ 0x42, 0x61, 0x51, 0x49, 0x46 }, // 2
{ 0x21, 0x41, 0x45, 0x4B, 0x31 }, // 3
{ 0x18, 0x14, 0x12, 0x7F, 0x10 }, // 4
{ 0x27, 0x45, 0x45, 0x45, 0x39 }, // 5
{ 0x3C, 0x4A, 0x49, 0x49, 0x30 }, // 6
{ 0x01, 0x71, 0x09, 0x05, 0x03 }, // 7
{ 0x36, 0x49, 0x49, 0x49, 0x36 }, // 8
{ 0x06, 0x49, 0x49, 0x29, 0x1E }, // 9
{ 0x00, 0x36, 0x36, 0x00, 0x00 }, // :
{ 0x00, 0x56, 0x36, 0x00, 0x00 }, // ;
{ 0x00, 0x08, 0x14, 0x22, 0x41 }, // <
{ 0x14, 0x14, 0x14, 0x14, 0x14 }, // =
{ 0x41, 0x22, 0x14, 0x08, 0x00 }, // >
{ 0x02, 0x01, 0x51, 0x09, 0x06 }, // ?
{ 0x32, 0x49, 0x79, 0x41, 0x3E }, // @
{ 0x7E, 0x11, 0x11, 0x11, 0x7E }, // A
{ 0x7F, 0x49, 0x49, 0x49, 0x36 }, // B
{ 0x3E, 0x41, 0x41, 0x41, 0x22 }, // C
{ 0x7F, 0x41, 0x41, 0x22, 0x1C }, // D
{ 0x7F, 0x49, 0x49, 0x49, 0x41 }, // E
{ 0x7F, 0x09, 0x09, 0x01, 0x01 }, // F
{ 0x3E, 0x41, 0x41, 0x51, 0x32 }, // G
{ 0x7F, 0x08, 0x08, 0x08, 0x7F }, // H
{ 0x00, 0x41, 0x7F, 0x41, 0x00 }, // I
{ 0x20, 0x40, 0x41, 0x3F, 0x01 }, // J
{ 0x7F, 0x08, 0x14, 0x22, 0x41 }, // K
{ 0x7F, 0x40, 0x40, 0x40, 0x40 }, // L
{ 0x7F, 0x02, 0x04, 0x02, 0x7F }, // M
{ 0x7F, 0x04, 0x08, 0x10, 0x7F }, // N
{ 0x3E, 0x41, 0x41, 0x41, 0x3E }, // O
{ 0x7F, 0x09, 0x09, 0x09, 0x06 }, // P
{ 0x3E, 0x41, 0x51, 0x21, 0x5E }, // Q
{ 0x7F, 0x09, 0x19, 0x29, 0x46 }, // R
{ 0x46, 0x49, 0x49, 0x49, 0x31 }, // S
{ 0x01, 0x01, 0x7F, 0x01, 0x01 }, // T
{ 0x3F, 0x40, 0x40, 0x40, 0x3F }, // U
{ 0x1F, 0x20, 0x40, 0x20, 0x1F }, // V
{ 0x7F, 0x20, 0x18, 0x20, 0x7F }, // W
{ 0x63, 0x14, 0x08, 0x14, 0x63 }, // X
{ 0x03, 0x04, 0x78, 0x04, 0x03 }, // Y
{ 0x61, 0x51, 0x49, 0x45, 0x43 }, // Z
{ 0x00, 0x00, 0x7F, 0x41, 0x41 }, // [
{ 0x02, 0x04, 0x08, 0x10, 0x20 }, // "\"
{ 0x41, 0x41, 0x7F, 0x00, 0x00 }, // ]
{ 0x04, 0x02, 0x01, 0x02, 0x04 }, // ^
{ 0x40, 0x40, 0x40, 0x40, 0x40 }, // _
{ 0x00, 0x01, 0x02, 0x04, 0x00 }, // `
{ 0x20, 0x54, 0x54, 0x54, 0x78 }, // a
{ 0x7F, 0x48, 0x44, 0x44, 0x38 }, // b
{ 0x38, 0x44, 0x44, 0x44, 0x20 }, // c
{ 0x38, 0x44, 0x44, 0x48, 0x7F }, // d
{ 0x38, 0x54, 0x54, 0x54, 0x18 }, // e
{ 0x08, 0x7E, 0x09, 0x01, 0x02 }, // f
{ 0x08, 0x14, 0x54, 0x54, 0x3C }, // g
{ 0x7F, 0x08, 0x04, 0x04, 0x78 }, // h
{ 0x00, 0x44, 0x7D, 0x40, 0x00 }, // i
{ 0x20, 0x40, 0x44, 0x3D, 0x00 }, // j
{ 0x00, 0x7F, 0x10, 0x28, 0x44 }, // k
{ 0x00, 0x41, 0x7F, 0x40, 0x00 }, // l
{ 0x7C, 0x04, 0x18, 0x04, 0x78 }, // m
{ 0x7C, 0x08, 0x04, 0x04, 0x78 }, // n
{ 0x38, 0x44, 0x44, 0x44, 0x38 }, // o
{ 0x7C, 0x14, 0x14, 0x14, 0x08 }, // p
{ 0x08, 0x14, 0x14, 0x18, 0x7C }, // q
{ 0x7C, 0x08, 0x04, 0x04, 0x08 }, // r
{ 0x48, 0x54, 0x54, 0x54, 0x20 }, // s
{ 0x04, 0x3F, 0x44, 0x40, 0x20 }, // t
{ 0x3C, 0x40, 0x40, 0x20, 0x7C }, // u
{ 0x1C, 0x20, 0x40, 0x20, 0x1C }, // v
{ 0x3C, 0x40, 0x30, 0x40, 0x3C }, // w
{ 0x44, 0x28, 0x10, 0x28, 0x44 }, // x
{ 0x0C, 0x50, 0x50, 0x50, 0x3C }, // y
{ 0x44, 0x64, 0x54, 0x4C, 0x44 }, // z
{ 0x00, 0x08, 0x36, 0x41, 0x00 }, // {
{ 0x00, 0x00, 0x7F, 0x00, 0x00 }, // |
{ 0x00, 0x41, 0x36, 0x08, 0x00 }, // }
{ 0x08, 0x08, 0x2A, 0x1C, 0x08 }, // ->
{ 0x08, 0x1C, 0x2A, 0x08, 0x08 }, // <-
};
// ---------------------------------------------------------------------------
// MISC ROUTINES
void SetupPorts() {
pinMode(RESET, OUTPUT);
pinMode(DC, OUTPUT);
pinMode(ChipSelect, OUTPUT);
digitalWrite(RESET, HIGH);
}
// calculate integer value of square root
unsigned long intsqrt(unsigned long val) {
unsigned long mulMask = 0x0008000;
unsigned long retVal = 0;
if (val > 0) {
while (mulMask != 0) {
retVal |= mulMask;
if ((retVal * retVal) > val) retVal &= ~ mulMask;
mulMask >>= 1;
}
}
return retVal;
}
// ---------------------------------------------------------------------------
// SPI ROUTINES
//
// b7 b6 b5 b4 b3 b2 b1 b0
// SPCR: SPIE SPE DORD MSTR CPOL CPHA SPR1 SPR0
// 0 1 0 1 . 0 0 0 1
//
// SPIE - enable SPI interrupt
// SPE - enable SPI
// DORD - 0=MSB first, 1=LSB first
// MSTR - 0=slave, 1=master
// CPOL - 0=clock starts low, 1=clock starts high
// CPHA - 0=read on rising-edge, 1=read on falling-edge
// SPRx - 00=osc/4, 01=osc/16, 10=osc/64, 11=osc/128
//
// SPCR = 0x50: SPI enabled as Master, mode 0, at 16/4 = 4 MHz
void OpenSPI() {
SPI.begin();
}
void CloseSPI() {
SPI.end();
}
byte Xfer(byte data) {
SPI.transfer(data);
}
// ---------------------------------------------------------------------------
// ST7735 ROUTINES
#define SWRESET 0x01 // software reset
#define SLPOUT 0x11 // sleep out
#define DISPOFF 0x28 // display off
#define DISPON 0x29 // display on
#define CASET 0x2A // column address set
#define RASET 0x2B // row address set
#define RAMWR 0x2C // RAM write
#define MADCTL 0x36 // axis control
#define COLMOD 0x3A // color mode
// 1.8" TFT display constants
#define XSIZE 128
#define YSIZE 160
#define XMAX XSIZE-1
#define YMAX YSIZE-1
void WriteCmd (byte cmd) {
digitalWrite(DC, LOW);
Xfer(cmd); // return DC high
digitalWrite(DC, HIGH);
}
void WriteByte (byte b) {
SPI.transfer(b);
}
void WriteWord (int w) {
SPI.transfer16(w);
}
// send 16-bit pixel data to the controller
// note: inlined spi xfer for optimization
//****************************************************************************
void Write565 (int data, unsigned int count) {
WriteCmd(RAMWR);
for (; count > 0; count--) SPI.transfer16(data);
}
//****************************************************************************
void HardwareReset() {
digitalWrite(RESET, LOW);
delay(1); // 1mS is enough
digitalWrite(RESET, HIGH);
delay(150); // wait 150mS for reset to finish
}
void InitDisplay() {
HardwareReset(); // initialize display controller
WriteCmd(SLPOUT); // take display out of sleep mode
delay(150); // wait 150mS for TFT driver circuits
WriteCmd(COLMOD); // select color mode:
WriteByte(0x05); // mode 5 = 16bit pixels (RGB565)
WriteCmd(DISPON); // turn display on!
}
void SetAddrWindow(byte x0, byte y0, byte x1, byte y1) {
WriteCmd(CASET); // set column range (x0,x1)
WriteWord(x0);
WriteWord(x1);
WriteCmd(RASET); // set row range (y0,y1)
WriteWord(y0);
WriteWord(y1);
}
void ClearScreen() {
SetAddrWindow(0, 0, XMAX, YMAX); // set window to entire display
WriteCmd(RAMWR);
for (word i = YSIZE * XSIZE * 2; i > 0; --i) SPI.transfer(0);
}
// ---------------------------------------------------------------------------
// SIMPLE GRAPHICS ROUTINES
//
// note: many routines have byte parameters, to save space,
// but these can easily be changed to int params for larger displays.
//****************************************************************************
void DrawPixel (byte x, byte y, int color) {
SetAddrWindow(x, y, x, y);
Write565(color, 1);
}
//****************************************************************************
// draws a horizontal line in given color
void HLine (byte x0, byte x1, byte y, int color) {
byte width = x1 - x0 + 1;
SetAddrWindow(x0, y, x1, y);
Write565(color, width);
}
// draws a vertical line in given color
void VLine (byte x, byte y0, byte y1, int color) {
byte height = y1 - y0 + 1;
SetAddrWindow(x, y0, x, y1);
Write565(color, height);
}
// an elegant implementation of the Bresenham algorithm
void Line (int x0, int y0, int x1, int y1, int color) {
int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
int dy = abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
int err = (dx > dy ? dx : -dy) / 2, e2;
for (;;) {
DrawPixel(x0, y0, color);
if (x0 == x1 && y0 == y1) break;
e2 = err;
if (e2 > -dx) {
err -= dy;
x0 += sx;
}
if (e2 < dy) {
err += dx;
y0 += sy;
}
}
}
// draws a rectangle in given color
void DrawRect (byte x0, byte y0, byte x1, byte y1, int color) {
HLine(x0, x1, y0, color);
HLine(x0, x1, y1, color);
VLine(x0, y0, y1, color);
VLine(x1, y0, y1, color);
}
void FillRect (byte x0, byte y0, byte x1, byte y1, int color) {
byte width = x1 - x0 + 1;
byte height = y1 - y0 + 1;
SetAddrWindow(x0, y0, x1, y1);
Write565(color, width * height);
}
// draws circle quadrant(s) centered at x,y with given radius & color
// quad is a bit-encoded representation of which cartesian quadrant(s) to draw.
// Remember that the y axis on our display is 'upside down':
// bit 0: draw quadrant I (lower right)
// bit 1: draw quadrant IV (upper right)
// bit 2: draw quadrant II (lower left)
// bit 3: draw quadrant III (upper left)
void CircleQuadrant (byte xPos, byte yPos, byte radius, byte quad, int color) {
int xEnd = (707 * radius) / 1000 + 1;
for (int x = 0; x < xEnd; x++) {
byte y = intsqrt(radius * radius - x * x);
if (quad & 0x01) {
DrawPixel(xPos + x, yPos + y, color); // lower right
DrawPixel(xPos + y, yPos + x, color);
}
if (quad & 0x02) {
DrawPixel(xPos + x, yPos - y, color); // upper right
DrawPixel(xPos + y, yPos - x, color);
}
if (quad & 0x04) {
DrawPixel(xPos - x, yPos + y, color); // lower left
DrawPixel(xPos - y, yPos + x, color);
}
if (quad & 0x08) {
DrawPixel(xPos - x, yPos - y, color); // upper left
DrawPixel(xPos - y, yPos - x, color);
}
}
}
// draws circle at x,y with given radius & color
void Circle (byte xPos, byte yPos, byte radius, int color) {
CircleQuadrant(xPos, yPos, radius, 0x0F, color); // do all 4 quadrants
}
// draws a rounded rectangle with corner radius r.
// coordinates: top left = x0,y0; bottom right = x1,y1
void RoundRect (byte x0, byte y0, byte x1, byte y1, byte r, int color) {
HLine(x0 + r, x1 - r, y0, color); // top side
HLine(x0 + r, x1 - r, y1, color); // bottom side
VLine(x0, y0 + r, y1 - r, color); // left side
VLine(x1, y0 + r, y1 - r, color); // right side
CircleQuadrant(x0 + r, y0 + r, r, 8, color); // upper left corner
CircleQuadrant(x1 - r, y0 + r, r, 2, color); // upper right corner
CircleQuadrant(x0 + r, y1 - r, r, 4, color); // lower left corner
CircleQuadrant(x1 - r, y1 - r, r, 1, color); // lower right corner
}
// draws filled circle at x,y with given radius & color
void FillCircle (byte xPos, byte yPos, byte radius, int color) {
long r2 = radius * radius;
for (int x = 0; x <= radius; x++) {
byte y = intsqrt(r2 - x * x);
byte y0 = yPos - y;
byte y1 = yPos + y;
VLine(xPos + x, y0, y1, color);
VLine(xPos - x, y0, y1, color);
}
}
// draws an ellipse of given width & height
// two-part Bresenham method
// note: slight discontinuity between parts on some (narrow) ellipses.
void Ellipse (int x0, int y0, int width, int height, int color) {
int a = width / 2, b = height / 2;
int x = 0, y = b;
long a2 = (long)a * a * 2;
long b2 = (long)b * b * 2;
long error = (long)a * a * b;
long stopY = 0, stopX = a2 * b;
while (stopY <= stopX) {
DrawPixel(x0 + x, y0 + y, color);
DrawPixel(x0 + x, y0 - y, color);
DrawPixel(x0 - x, y0 + y, color);
DrawPixel(x0 - x, y0 - y, color);
x++;
error -= b2 * (x - 1);
stopY += b2;
if (error < 0) {
error += a2 * (y - 1);
y--;
stopX -= a2;
}
}
x = a; y = 0; error = b * b * a;
stopY = a * b2; stopX = 0;
while (stopY >= stopX) {
DrawPixel(x0 + x, y0 + y, color);
DrawPixel(x0 + x, y0 - y, color);
DrawPixel(x0 - x, y0 + y, color);
DrawPixel(x0 - x, y0 - y, color);
y++;
error -= a2 * (y - 1);
stopX += a2;
if (error < 0) {
error += b2 * (x - 1);
x--;
stopY -= b2;
}
}
}
// draws a filled ellipse of given width & height
void FillEllipse(int xPos, int yPos, int width, int height, int color) {
int a = width / 2, b = height / 2; // get x & y radii
int x1, x0 = a, y = 1, dx = 0;
long a2 = a * a, b2 = b * b; // need longs: big numbers!
long a2b2 = a2 * b2;
HLine(xPos - a, xPos + a, yPos, color); // draw centerline
// draw horizontal lines...
while (y <= b) {
for (x1 = x0 - (dx - 1); x1 > 0; x1--)
if (b2 * x1 * x1 + a2 * y * y <= a2b2)
break;
dx = x0 - x1;
x0 = x1;
HLine(xPos - x0, xPos + x0, yPos + y, color);
HLine(xPos - x0, xPos + x0, yPos - y, color);
y += 1;
}
}
// ---------------------------------------------------------------------------
// TEXT ROUTINES
//
// Each ASCII character is 5x7, with one pixel space between characters
// So, character width = 6 pixels & character height = 8 pixels.
//
// In portrait mode:
// Display width = 128 pixels, so there are 21 chars/row (21x6 = 126).
// Display height = 160 pixels, so there are 20 rows (20x8 = 160).
// Total number of characters in portait mode = 21 x 20 = 420.
//
// In landscape mode:
// Display width is 160, so there are 26 chars/row (26x6 = 156).
// Display height is 128, so there are 16 rows (16x8 = 128).
// Total number of characters in landscape mode = 26x16 = 416.
byte curX, curY; // current x & y cursor position
// position cursor on character x,y grid, where 0<x<20, 0<y<19.
void GotoXY (byte x, byte y) {
curX = x;
curY = y;
}
// position character cursor to start of line y, where 0<y<19.
void GotoLine(byte y) {
curX = 0;
curY = y;
}
// moves character cursor to next position, assuming portrait orientation
void AdvanceCursor() {
curX++; // advance x position
// beyond right margin?
if (curX > 20) {
curY++; // go to next line
curX = 0; // at left margin
}
// beyond bottom margin?
if (curY > 19) curY = 0; // start at top again
}
// Set the display orientation to 0,90,180,or 270 degrees
void SetOrientation(int degrees) {
byte arg;
switch (degrees) {
case 90: arg = 0x60; break;
case 180: arg = 0xC0; break;
case 270: arg = 0xA0; break;
default: arg = 0x00; break;
}
WriteCmd(MADCTL);
WriteByte(arg);
}
// write ch to display X,Y coordinates using ASCII 5x7 font
void PutCh (char ch, byte x, byte y, int color) {
int pixel;
byte bit, data, mask = 0x01;
SetAddrWindow(x, y, x + 4, y + 6);
WriteCmd(RAMWR);
for (byte row = 0; row < 7; row++) {
for (byte col = 0; col < 5; col++) {
data = pgm_read_byte(&(FONT_CHARS[ch - 32][col]));
bit = data & mask;
if (bit == 0) pixel = BLACK;
else pixel = color;
WriteWord(pixel);
}
mask <<= 1;
}
}
// writes character to display at current cursor position.
void WriteChar(char ch, int color) {
PutCh(ch, curX * 6, curY * 8, color);
AdvanceCursor();
}
// writes string to display at current cursor position.
void WriteString(char *text, int color) {
for (; *text; text++) // for all non-nul chars
WriteChar(*text, color); // write the char
}
// writes integer i at current cursor position
void WriteInt(int i) {
char str[8]; // buffer for string result
itoa(i, str, 10); // convert to string, base 10
WriteString(str, WHITE);
}
// writes hexadecimal value of integer i at current cursor position
void WriteHex(int i) {
char str[8]; // buffer for string result
itoa(i, str, 16); // convert to base 16 (hex)
WriteString(str, WHITE);
}
// ---------------------------------------------------------------------------
// TEST ROUTINES
// draws 4000 pixels on the screen
void PixelTest() {
// do a whole bunch:
for (int i = 4000; i > 0; i--) {
int x = rand() % XMAX; // random x coordinate
int y = rand() % YMAX; // random y coordinate
DrawPixel(x, y, YELLOW); // draw pixel at x,y
}
}
// sweeps Line routine through all four quadrants.
void LineTest() {
ClearScreen();
int x0 = 64, y0 = 80;
for (int x = 0; x < XMAX; x += 2) Line(x0, y0, x, 0, YELLOW);
for (int y = 0; y < YMAX; y += 2) Line(x0, y0, XMAX, y, CYAN);
for (int x = XMAX; x > 0; x -= 2) Line(x0, y0, x, YMAX, YELLOW);
for (int y = YMAX; y > 0; y -= 2) Line(x0, y0, 0, y, CYAN);
//delay(2000);
}
// draw series of concentric circles
void CircleTest() {
for (int radius = 6; radius < 60; radius += 2)
Circle(60, 80, radius, YELLOW);
}
// Writes 420 characters (5x7) to screen in portrait mode
void PortraitChars() {
ClearScreen();
for (int i = 420; i > 0; i--) {
byte x = i % 21;
byte y = i / 21;
char ascii = (i % 96) + 32;
PutCh(ascii, x * 6, y * 8, CYAN);
}
//delay(2000);
}
Comments