ESP32 and Round OLED Smart Watch Concept 1
ESP32 and Round OLED Smart Watch Concept 1
ESP32 and Round OLED Smart Watch Concept 1
by Arnov Sharma
https://youtu.be/WSKonGVJNYk
GC9A01 is a 240x240 Round RGB LCD Display that adopts a four-wire SPI communication interface, SPI is fast so it can
greatly save the GPIO port, and the communication speed will be faster.
It's similar in size to the 240x240 square LCD but has rounded edges.
ESP32 and Round OLED Smart Watch Concept: Page 2
The built-in driver used in this LCD is GC9A01, with a resolution of 240RGB×240 dots.
Checkout its wiki page for more info- https://www.waveshare.com/wiki/1.28inch_LCD_Module
Following are its electrical parameters-
Operating voltage: 3.3V/5V
Interface: SPI
LCD type: IPS
Controller: GC9A01
Resolution: 240(H)RGB x 240(V)
Display size: Φ32.4mm
Pixel size: 0.135 H x0.135 V mm
Dimension: 40.4×37.5(mm) Φ37.5(mm)
This display was made by Waveshare and you could nd all info about this display on their site.
Here's the link- https://www.waveshare.com/product/1.28inch-lcd-module.htm
On their page, they have used an Arduino Uno to run the board, also a Raspberry pi, and a Nucleo Board but we're going
to use the ESP32 board because of its connectivity features and faster processing power.
As for sourcing this display, I got this display from PCBWAY's Giftshop.
Aside from PCB Services, PCBWAY also has a dedicated components store.
PCBWAY GIFTSHOP is an online marketplace from where we can source all the major electronics stu , like Arduino
boards, Raspberry Pi boards, Modules, sensors, etc.
PCBWAY have this system that lets us purchase anything from their gift shop through beans, Beans are like a redeemable
currency or coupons that we get by placing an order on PCBWAY or by sharing your projects in the community to get
beans.
Check PCBWAY out for getting great PCB service from here- https://www.pcbway.com/
To run this OLED with ESP32, I used the popular TFT_eSPI Library by Bodmer.
https://github.com/Bodmer/TFT_eSPI
TFT_eSPI is an amazing library that supports all major displays that are used, like ILI9430, ST7735, and even the round
LCD GC9A01.
We rst go to its Github Page and download the RAW les.
Next, we extract the folder in Documents>Arduino>Libraries where we keep all our custom libraries.
We Open the Arduino IDE and see the TFT_eSPI added in the library manager.
Before testing this display, we need to do some editing on the user setup le.
we go to C:\Users\ACER\Documents\Arduino\libraries\TFT_eSPI and make changes in the User
Setup.h by replacing it with User setup for GC9A01.
The default one is set for ILI9430 Display and we change it for GC9A01 by adding // in front of ILI9430 User
setup and removing // in front of GC9A01.
We rst connect VCC and BL, we do this to supply BL which is backlight 3.3V through the MCU.
GND to GND of ESP32
Din to D23 which is MOSI Pin
ESP32 and Round OLED Smart Watch Concept: Page 8
CLK to D19 which is SCK
CS to D15 Pin
DC to D2 Pin
RST to D4 Pin
#include "graphic.h"
void setup() {
Serial.begin(115200);
// while(!Serial);
tft.begin();
tft.setRotation(3); // Landscape orientation, USB at bottom right
tft.setSwapBytes(false);
// Draw initial framebuffer contents:
//tft.setBitmapColor(GRIDCOLOR, BGCOLOR);
tft.fillScreen(BGCOLOR);
tft.initDMA();
startTime = millis();
}
void loop() {
// Start SPI transaction and drop TFT_CS - avoids transaction overhead in loop
tft.startWrite();
bufIdx = 1 - bufIdx;
by++; // Increment bitmap position counters (Y axis)
bgy++;
}
//if (random(100) == 1) delay(2000);
tft.endWrite();
//delay(5);
// Show approximate frame rate
if(!(++frame & 255)) { // Every 256 frames...
uint32_t elapsed = (millis() - startTime) / 1000; // Seconds
if(elapsed) {
Serial.print(frame / elapsed);
Serial.println(" fps");
}
}
}
Second Sketch will be this Scrolling Sprite Message which can be found in Example>TFT_eSPI> Sprite>ScrollingSprite
16 Bit
#define IWIDTH 240
#define IHEIGHT 30
ESP32 and Round OLED Smart Watch Concept: Page 12
#define IHEIGHT 30
#include <TFT_eSPI.h> // Include the graphics library (this includes the sprite functions)
TFT_eSprite img = TFT_eSprite(&tft); // Create Sprite object "img" with pointer to "tft" object
// // the pointer is used by pushSprite() to push it onto the TFT
// -------------------------------------------------------------------------
// Setup
// -------------------------------------------------------------------------
void setup(void) {
tft.init();
tft.setRotation(0);
tft.fillScreen(TFT_BLUE);
}
// -------------------------------------------------------------------------
// Main loop
// -------------------------------------------------------------------------
void loop() {
while (1)
{
// Create the sprite and clear background to black
img.createSprite(IWIDTH, IHEIGHT);
//img.fillSprite(TFT_BLACK); // Optional here as we fill the sprite later anyway
delay(WAIT);
}
}
}
// #########################################################################
// Build the scrolling sprite image from scratch, draw text at x = xpos
// #########################################################################
// Draw some graphics, the text will apear to scroll over these
img.fillRect (IWIDTH / 2 - 20, IHEIGHT / 2 - 10, 40, 20, TFT_YELLOW);
img.fillCircle(IWIDTH / 2, IHEIGHT / 2, 10, TFT_ORANGE);
// #########################################################################
// Create sprite, plot graphics in it, plot to screen, then delete sprite
// #########################################################################
void numberBox(int num, int x, int y)
{
// Create a sprite 80 pixels wide, 50 high (8kbytes of RAM needed)
img.createSprite(80, 50);
// Push sprite to TFT screen CGRAM at coordinate x,y (top left corner)
img.pushSprite(x, y);
// #########################################################################
// 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 = red through to 127 = blue
switch (sector)
{
case 0:
red = 0x1F;
green = amplit;
blue = 0;
break;
case 1:
red = 0x1F - amplit;
green = 0x1F;
blue = 0;
break;
case 2:
red = 0;
green = 0x1F;
blue = amplit;
break;
case 3:
red = 0;
ESP32 and Round OLED Smart Watch Concept: Page 14
red = 0;
green = 0x1F - amplit;
blue = 0x1F;
break;
}
Here's the smartwatch code that was originally made by Volos Project.
https://github.com/VolosR/watchESP
It consists of the main le and one header le, header le contains fonts that are used in the main sketch.
#include <TFT_eSPI.h>
#include "fonts.h"
#include "time.h"
#include "RTClib.h"
RTC_DS3231 rtc;
TFT_eSPI tft = TFT_eSPI();
TFT_eSprite img = TFT_eSprite(&tft);
#define color1 TFT_WHITE
#define color2 0x8410
#define color3 0x5ACB
#define color4 0x15B3
#define color5 0x00A3
volatile int counter = 0;
float VALUE;
float lastValue=0;
double rad=0.01745;
float x[360];
float y[360];
float px[360];
float py[360];
float lx[360];
float ly[360];
int r=104;
int sx=120;
int sy=120;
String cc[12]={"45","40","35","30","25","20","15","10","05","0","55","50"};
String days[]={"SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY"};
int start[12];
int startP[60];
const int pwmFreq = 5000;
const int pwmResolution = 8;
const int pwmLedChannelTFT = 0;
int angle=0;
bool onOff=0;
bool debounce=0;
String h,m,s,d1,d2,m1,m2;
void setup() {
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
}
pinMode(2,OUTPUT);
pinMode(0,INPUT_PULLUP);
pinMode(35,INPUT_PULLUP);
pinMode(13,INPUT_PULLUP);
digitalWrite(2,0);
ledcSetup(pwmLedChannelTFT, pwmFreq, pwmResolution);
ledcAttachPin(5, pwmLedChannelTFT);
ledcWrite(pwmLedChannelTFT, 200);
tft.init();
tft.setSwapBytes(true);
tft.fillScreen(TFT_BLACK);
img.setSwapBytes(true);
img.createSprite(240, 240);
img.setTextDatum(4);
int b=0;
int b2=0;
for(int i=0;i<360;i++)
{
x[i]=(r*cos(rad*i))+sx;
y[i]=(r*sin(rad*i))+sy;
px[i]=((r-16)*cos(rad*i))+sx;
py[i]=((r-16)*sin(rad*i))+sy;
lx[i]=((r-26)*cos(rad*i))+sx;
ly[i]=((r-26)*sin(rad*i))+sy;
if(i%30==0){
start[b]=i;
ESP32 and Round OLED Smart Watch Concept: Page 16
start[b]=i;
b++;
}
if(i%6==0){
startP[b2]=i;
b2++;
}
}
}
int lastAngle=0;
float circle=100;
bool dir=0;
int rAngle=359;
void loop() {
rAngle=rAngle-2;
DateTime now = rtc.now();
angle=now.second()*6;
s=String(now.second());
m=String(now.minute());
h=String(now.hour());
if(m.toInt()<10)
m="0"+m;
if(h.toInt()<10)
h="0"+h;
if(s.toInt()<10)
s="0"+s;
if(now.day()>10)
{
d1=now.day()/10;
d2=now.day()%10;
}
else
{
d1="0";
d2=String(now.day());
}
if(now.month()>10)
{
m1=now.month()/10;
m2=now.month()%10;
}
else
{
m1="0";
m2=String(now.month());
}
if(angle>=360)
angle=0;
if(rAngle<=0)
rAngle=359;
if(dir==0)
circle=circle+0.5;
else
circle=circle-0.5;
if(circle>140)
dir=!dir;
if(circle<100)
dir=!dir;
if(angle>-1)
{
lastAngle=angle;
VALUE=((angle-270)/3.60)*-1;
if(VALUE<0)
VALUE=VALUE+100;
img.fillSprite(TFT_BLACK);
img.fillCircle(sx,sy,124,color5);
img.setTextColor(TFT_WHITE,color5);
img.drawString(days[now.dayOfTheWeek()],circle,120,2);
for(int i=0;i<12;i++)
if(start[i]+angle<360){
img.drawString(cc[i],x[start[i]+angle],y[start[i]+angle],2);
img.drawLine(px[start[i]+angle],py[start[i]+angle],lx[start[i]+angle],ly[start[i]+angle],color1);
}
else
{
img.drawString(cc[i],x[(start[i]+angle)-360],y[(start[i]+angle)-360],2);
This Sketch is great but it requires a Real Time Clock Module which is missing from the current setup.
Instead of this sketch, we use another sketch that is available in example sketches.
This will be the nal sketch that will be used in version 2 of this smartwatch project with a few tweaks, this sketch can be
found in the Example>TFT_eSPI> 320x240>TFT_Clock_Digital
I did some medications in the original sketch so it won't display the seconds time and only displays hours and minutes.
Here's the edited sketch-
#include <TFT_eSPI.h> // Hardware-specific library
#include <SPI.h>
static uint8_t conv2d(const char* p); // Forward declaration needed for IDE 1.6.x
uint8_t hh = conv2d(__TIME__), mm = conv2d(__TIME__ + 3), ss = conv2d(__TIME__ + 6); // Get H, M, S from compile time
void setup(void) {
//Serial.begin(115200);
tft.init();
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
tft.setTextSize(1);
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
void loop() {
if (targetTime < millis()) {
// Set next update for 1 second later
targetTime = millis() + 1000;
//Draw seconds
if (ss < 10) xpos += tft.drawChar('0', xpos, ysecs, 6); // Add leading zero
// tft.drawNumber(ss, xpos, ysecs, 6); // Draw seconds
}
}
}
For Version 2, The plan is to prepare a PCB that will have an ESP32 WROOM-32 Module and an Onboard Battery
management system so we can add a 3.7V Lipo cell and it will power this watch.
https://youtu.be/WSKonGVJNYk