UPDATE: I’ve now started a GitHub repository, and uploaded the code there:
https://github.com/michaelbapst/CYD-ESP32-2432S028R/tree/main
I’ve also made more versions of Name Badge:
NameBadge2: Removed the enormous Switch/Case statement and replaced it with 2D String array.
NameBadge3: Added code to change the Random Number seed with the X * Y of where the screen has been touched, thereby changing how the list of names get’s displayed.
Cheap Yellow Display (CYD)
I recently stumbled across Brian Lough’s [witnessmenow] ESP32 Cheap Yellow Display git hub page, via Hackaday’s Article about the CYD. The Cheap Yellow Display is an ESP32 development board with the following features:
- ESP32 (With Wifi and Bluetooth)
- 320 x 240 LCD Display (2.8″)
- Touch Screen (Resistive)
- USB for powering and programming
- SD Card Slot, LED and some additional pins broken out
I purchased mine through Ali Express for $6.94USD including shipping, and I got it in less than 2 weeks. There are a number of projects on a variety of git repositories. You can find a list here. One of my personal favorites is ESP32-Marauder, which turns the CYD into a neat little WIFI/Bluetooth hacking device.
Once you get your CYD, you’ll need to set it up, and here are detailed instructions. Make sure you follow them completely, setup your Arduino IDE with the correct libraries, and install User_Setup.h in <USERNAME>\Documents\Arduino\libraries\TFT_eSPI. Nothing using the TFT_eSPI Library will work with out the User_Setup.h installed.
Since I am playing Odin at my local renaissance faire this Autumn, I wanted to an electronic name badge that randomly shows 1 of 96 names of Odin both in English and Elder Futhark Runes. I started by using the code from “Hello World” for Cheap Yellow Display by Brian Lough, added code snippets from other examples, encoded a runic font file (FutharkAOE28 Is based on Futhark AOE Regular Brian J. Bonislawsky astigma@astigmatic.com), and some help from Microsoft’s Copilot AI. I haven’t written anything in C language since the ’90’s, and I haven’t done any real coding in over 15 years. Copilot was a huge help. Here is a video of the end product:
I’m quite happy with the end product. I’m sure the code could be further optimized. Like I said, I haven’t done this in a very long time. Instead of using a giant Switch/Case statement, I probably could have grabbed a name from a text file on an sdcard. But I didn’t want to fiddle with fileIO, and this code works without having an sdcard installed. You can download the code from GitHub, or follow along below:
(Updated to NameBadge3)
namebadge3.ino
/*******************************************************************
Name Badge
Adapted by Michael Bapst (https://www.einherjar.org)
Name Badge is based on "Hello World" for the ESP32 Cheap Yellow Display.
https://github.com/witnessmenow/ESP32-Cheap-Yellow-Display
Written by Brian Lough
YouTube: https://www.youtube.com/brianlough
Twitter: https://twitter.com/witnessmenow
Touch code was taken from Rui Santos & Sara Santos - Random Nerd Tutorials
Additional code was supplied by Microsoft Copilot, who helped me remember
a lot of C/C++, which I hadn't touched since the 90's
*******************************************************************/
// Make sure to copy the UserSetup.h file into the library as
// per the Github Instructions. The pins are defined in there.
#include <string>
#include "NotoSansBold36.h"
#include "FutharkAOE.h"
#include "namelist.h"
// The font names are arrays references, thus must NOT be in quotes ""
#define AA_FONT_LARGE NotoSansBold36
#define AA_FONT_RUNIC FutharkAOE28
#define Name_List cNameList
#include <SPI.h>
// A library for interfacing with LCD displays
// Can be installed from the library manager (Search for "TFT_eSPI")
//https://github.com/Bodmer/TFT_eSPI
#include <TFT_eSPI.h> // Hardware-specific library
TFT_eSPI tft = TFT_eSPI();
// Install the "XPT2046_Touchscreen" library by Paul Stoffregen to use the Touchscreen - https://github.com/PaulStoffregen/XPT2046_Touchscreen
// Note: this library doesn't require further configuration
#include <XPT2046_Touchscreen.h>
// Touchscreen pins
#define XPT2046_IRQ 36 // T_IRQ
#define XPT2046_MOSI 32 // T_DIN
#define XPT2046_MISO 39 // T_OUT
#define XPT2046_CLK 25 // T_CLK
#define XPT2046_CS 33 // T_CS
// Touchscreen coordinates: (x, y) and pressure (z)
int x, y, z;
SPIClass touchscreenSPI = SPIClass(VSPI);
XPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);
void RNDSeedTouch(int touchX, int touchY, int touchZ) {
srand(touchX * touchY);
}
void setup() {
//Initial Random seed value. The random seed will change when you touch the screen
srand(69); //Nice...
touchscreenSPI.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);
touchscreen.begin(touchscreenSPI);
// Set the Touchscreen rotation in landscape mode
// Note: in some displays, the touchscreen might be upside down, so you might need to set the rotation to 3: touchscreen.setRotation(3);
touchscreen.setRotation(1);
// Start the tft display and set it to black
tft.init();
tft.setRotation(1); //This is the display in landscape
// Clear the screen before writing to it
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_YELLOW, TFT_BLACK, true);
tft.drawString("HELLO, MY NAME IS...", 5, 10, 4); // Left Aligned
tft.drawCentreString("(ODIN)", 160, 200, 2);
tft.loadFont(AA_FONT_LARGE); // Must load the font first
tft.setTextColor(TFT_WHITE, TFT_BLACK, true);
tft.drawCentreString("Michael", 160, 90, 4); //Center Aligned
tft.unloadFont(); // Remove the font to recover memory used
delay(3000);
}
void loop() {
//Checks to see if the screen has been touched, and if it has
//Seed the random number with X * Y of where the screen has been touched.
if (touchscreen.tirqTouched() && touchscreen.touched()) {
// Get Touchscreen points
TS_Point p = touchscreen.getPoint();
// Calibrate Touchscreen points with map function to the correct width and height
x = map(p.x, 200, 3700, 1, 320);
y = map(p.y, 240, 3800, 1, 240);
z = p.z;
RNDSeedTouch(x, y, x);
// Uncomment the next two lines to print the new random seed to the screen.
//tft.setTextColor(TFT_WHITE, TFT_BLACK, true);
//tft.drawCentreString(String(x * y), 160, 220, 2);
delay(100);
}
int rndNumber = rand() % 96; //Pick a number between 0 and 96
//Randomly selected name so it doesn't look like your going down an alphabetical list
//Print Name in Roman Characters
tft.loadFont(AA_FONT_LARGE); // Must load the font first]
//Blank out old text instead of clearing the screen. This prevents screen flashing
tft.setTextColor(TFT_WHITE, TFT_BLACK, true);
tft.drawCentreString(" ", 160, 90, 4);
tft.drawCentreString(Name_List[rndNumber][0], 160, 90, 4); //Write new text
tft.unloadFont(); // Remove the font to recover memory used
//Print Name is Runic Characters
tft.loadFont(AA_FONT_RUNIC); // Must load the font first
tft.setTextColor(TFT_RED, TFT_BLACK, true);
tft.drawCentreString(" ", 160, 140, 4); //Clear old text
tft.drawCentreString(Name_List[rndNumber][1], 160, 140, 4); //Write new text
tft.unloadFont(); // Remove the font to recover memory used
delay(2000); //wait 2 seconds and start over
}
namelist.h
/* *****************************************************************************************
A list of Odhinn's names
Odin has 170 different names. More if you count the different spellings of the same name:
ODIN -> ODHINN -> OTHEN -> WODEN -> WOTAN
Here I have selected 96 of them.
The first name is Old Norse ---> English spelling
The Second Name is the Rune friendly Spelling (Y=I, C=K, V=W, etc.)
*******************************************************************************************/
const String cNameList[96][2] = {
{ "Alfadhr", "alfadhr" },
{ "Aldagautr", "aldagautr" },
{ "Atridhr", "atridhr" },
{ "Asagrim", "asagrim" },
{ "Audhun", "audhun" },
{ "Baleygr Baleyg", "baleigr baleig" },
{ "Biflindi", "biflindi" },
{ "Blindr", "blindr" },
{ "Bolverkr", "bolwerkr" },
{ "Draugadrottinn", "draugadrottinn" },
{ "Dresvarpr", "dreswarpr" },
{ "Drottinn", "drottinn" },
{ "Farmagnudhr", "farmagnudhr" },
{ "Farmatyr", "farmatir" },
{ "Fimbultyr", "fimbultir" },
{ "Fimbulthulr", "fimbulthulr" },
{ "Fjolnir", "fjolnir" },
{ "Fjolsvidhr", "fjolswidhr" },
{ "Foldardrottinn", "foldardrottinn" },
{ "Forni", "forni" },
{ "Gagnradhr", "gagnradhr" },
{ "Galdrafodhr", "galdrafodhr" },
{ "Fadhir galdrs", "fadhir galdrs" },
{ "Ganglari", "ganglari" },
{ "Gautr", "gautr" },
{ "Geirtyr", "geirtir" },
{ "Geirvaldr", "geirwaldr" },
{ "Glapsvidhr", "glapswidhr" },
{ "Gondlir", "gondlir" },
{ "Grimnir", "grimnir" },
{ "Gunnblindi", "gunnblindi" },
{ "Hagvirkr", "hagwirkr" },
{ "Hangadrottinn", "hangadrottinn" },
{ "Hangatyr", "hangatir" },
{ "Hangi", "hangi" },
{ "Haptagudh", "haptagudh" },
{ "Harbardhr", "harbardhr" },
{ "Harr", "harr" },
{ "Havi", "hawi" },
{ "Helblindi", "helblindi" },
{ "Herjafodhr", "herjafodhr" },
{ "Herjan", "herjan" },
{ "Herteitr", "herteitr" },
{ "Hildolfr", "hildolfr" },
{ "Hjaldrgegnir", "hjaldrgegnir" },
{ "Hjalmberi", "hjalmberi" },
{ "Hnikarr", "hnikarr" },
{ "Hoarr", "hoarr" },
{ "Hrafnagudh", "hrafnagudh" },
{ "Hroptatyr", "hroptatir" },
{ "Jafnharr", "jafnharr" },
{ "Odhinn", "odhinn" },
{ "Ofnir", "ofnir" },
{ "Reidhartyr", "reidhartir" },
{ "Rognir", "rognir" },
{ "Runatyr", "runatir" },
{ "Sadhr", "sadhr" },
{ "Sanngetall", "sanngetall" },
{ "Sidhgrani", "sidhgrani" },
{ "Sidhhottr", "sidhhottr" },
{ "Sidhskeggr", "sidhskeggr" },
{ "Sigfodhr", "sigfodhr" },
{ "Sigrunnr", "sigrunnr" },
{ "Sigtryggr", "sigtriggr" },
{ "Sigtyr", "sigtir" },
{ "Sigthror", "sigthror" },
{ "Skilfingr", "skilfingr" },
{ "Skollvaldr", "skollwaldr" },
{ "Svafnir", "swafnir" },
{ "Sveigdhir", "sweigdhir" },
{ "Svidhrir", "swidhrir" },
{ "Svipall", "swipall" },
{ "Svolnir", "swolnir" },
{ "Tviblindi", "twiblindi" },
{ "Thekkr", "thekkr" },
{ "Thrasarr", "thrasarr" },
{ "Thridhi", "thridhi" },
{ "Thriggi", "thriggi" },
{ "Throttr", "throttr" },
{ "Udhr", "udhr" },
{ "Vafudhr", "wafudhr" },
{ "Valfodhr", "walfodhr" },
{ "Valgautr", "walgautr" },
{ "Valkjosandi", "walkjosandi" },
{ "Valtamr", "waltamr" },
{ "Valtyr", "waltir" },
{ "Valthognir", "walthognir" },
{ "Vegtam", "wegtam" },
{ "Veratyr", "weratir" },
{ "Vidhfrager", "widhfrager" },
{ "Vidhrir", "widhrir" },
{ "Vidhrimnir", "widhrimnir" },
{ "Vidhurr", "widhurr" },
{ "Vingnir", "wingnir" },
{ "Woden", "woden" },
{ "Wotan", "wotan" },
};
NotoSansBold36.h – Too large to display.
FutharkAOE.h – Too large to display
(Listing the above files is giving WordPress a complete fit. Removed for now. Download the project from GitHub.)