# [EN] How to make the stopwatch?

From the article Create a clock that displays an analog display through a color display, this time, it has been modified to make it work as a timer or stopwatch by using the ESP32-CAM board connected to the TFT display and using a switch from pin GPIO0 used as a mode switch or program chip when booting the system or supply power to board ESP32-CAM as shown in Figure 1 and programming still uses Python language with MicroPython as always

Draw a clock

The improvements from the previous article are to change the style of the pins on the watch face. By drawing a change from drawing a circle from the calculated midpoint of each position to draw in a straight line. The working processes of this section are

• calculate for newX, newY
• calculate newX2 และ newY2
• draw straight line from (newX, newY) to (newX2, newY2)

The result is as shown in Figure 2, and the code for drawing the watch face is as follows.

``````screenCenterX = 40
screenCenterY = 40
...
def drawClock():
midPointCircleDraw(screenCenterX, screenCenterY, 39, tft.color(232,232,232))
n12x = screenCenterX
n12y = 2
n12y2 = 8
for i in range(12):
newX,newY = rotate( n12x, n12y, 30*i)
newX2,newY2 = rotate( n12x, n12y2, 30*i)
tft.line((newX,newY),(newX2, newY2),tft.color(232, 232, 64))``````

Example Code

Circuit

Equipment

1.  ST7735 GREENTAB80x160 display
2. ESP32 , we use ESP32CAM

Connecting from display to ESP32 using channel 2 SPI bus

1. SCK of display connect to GPIO14 of ESP32
2. MOSI of display connect to GPIO12 of ESP32
3. DC of display connect to GPIO15 of ESP32
4. RST of display connect to GPIO13 of ESP32
5. CS of display connect to GPIO2 of ESP32

Connecting the switch to the GPIO0 pin

Code

The working principles of the sample program are

• Set the working load to 0.
• Draw a dial.
• if switch was pressed
• if state = 0
• start timer
• change state to 1
• if state = 1
• stop timer
• show hour, minute, second
• clear the variables to default

Code

``````from ST7735 import TFT
import machine as mc
from machine import SPI,Pin, Timer
import time
import math

#################################################################
###### setting ##################################################
#################################################################
mc.freq(240000000)
spi = SPI(2, baudrate=26000000,
sck=Pin(14), mosi=Pin(12),
polarity=0, phase=0)
sw = Pin(0, Pin.IN, Pin.PULL_UP)
# dc, rst, cs
tft=TFT(spi,15,13,2)
tft.fill(tft.BLACK)
tft.swap()
screenCenterX = 40
screenCenterY = 40
second = 0
minute = 0
hour = 0
state = 0

#################################################################
###### sub modules ##############################################
#################################################################
def midPointCircleDraw(x_centre, y_centre, r, c):
x = r
y = 0

tft.setPixel(x + x_centre,y + y_centre, c)

# When radius is zero only a single
# point be printed
if (r > 0) :
tft.setPixel(x + x_centre,-y + y_centre, c)
tft.setPixel(y + x_centre,x + y_centre, c)
tft.setPixel(-y + x_centre,x + y_centre, c)

# Initialising the value of P
P = 1 - r

while x > y:
y += 1

# Mid-point inside or on the perimeter
if P <= 0:
P = P + 2 * y + 1

# Mid-point outside the perimeter
else:
x -= 1
P = P + 2 * y - 2 * x + 1

# All the perimeter points have
# already been printed
if (x < y):
break

# Printing the generated point its reflection
# in the other octants after translation
tft.setPixel(x + x_centre,y + y_centre, c)
tft.setPixel(-x + x_centre, y + y_centre, c)
tft.setPixel( x + x_centre,-y + y_centre, c)
tft.setPixel( -x + x_centre,-y + y_centre, c)

# If the generated point on the line x = y then
# the perimeter points have already been printed
if x != y:
tft.setPixel(y + x_centre, x + y_centre, c)
tft.setPixel(-y + x_centre, x + y_centre, c)
tft.setPixel(y + x_centre, -x + y_centre, c)
tft.setPixel(-y + x_centre, -x + y_centre, c)

def rotate(pX,pY,angle):
pX -= screenCenterX
pY -= screenCenterY
newX = xCos - ySin + screenCenterX
newY = xSin + yCos + screenCenterY
return (int(newX), int(newY))

def drawClock():
midPointCircleDraw(screenCenterX, screenCenterY, 39, tft.color(232,232,232))
n12x = screenCenterX
n12y = 2
n12y2 = 8
for i in range(12):
newX,newY = rotate( n12x, n12y, 30*i)
newX2,newY2 = rotate( n12x, n12y2, 30*i)
tft.line((newX,newY),(newX2, newY2),tft.color(232, 232, 64))

def drawSecond( sec ):
deg = sec*6
n12x = screenCenterX
n12y = 10
newX,newY = rotate( n12x, n12y, deg)
tft.line((screenCenterX, screenCenterY), (newX, newY), tft.color(232, 64, 232))

def cbSecond(x):
global second, minute, hour
second += 1
if (second == 60):
second = 0
minute += 1
if (minute == 60):
minute = 0
hour += 1
if (hour == 12):
hour = 0
tft.fill(tft.BLACK)
drawClock()
drawSecond(second)
tft.swap()

#################################################################
###### main program #############################################
#################################################################
tft.fill(tft.BLACK)
drawClock()
drawSecond(0)
tft.swap()
secTmr = Timer(0)
while True:
if (sw.value()==0):
if state == 0:
secTmr.init( period=1000, mode=Timer.PERIODIC, callback=cbSecond)
state = 1 # start
else:
state = 0
secTmr.deinit()
tft.fill(tft.BLACK)
drawClock()
drawSecond(0)
tft.text("H:{}".format(hour),(96,24),tft.color(232, 192, 194))
tft.text("M:{}".format(minute),(96,34),tft.color(192, 232, 194))
tft.text("S:{}".format(second),(96,44),tft.color(194, 192, 232))
tft.swap()
second = 0
minute = 0
hour = 0
time.sleep(0.25)

``````

The result is as shown it Figure 3

Conclusion

From this article, we can see that we can improve the function of the watch as a timer by modifying the working procedure. Making the original equipment more capable means the hardware that we use will work very well, besides the hardware design being good, it also depends on the software we write. We hope that the examples in this article should serve as a guide for improving functionality or combine it with the previous article to support more functionality and finally, have fun with programming.

(C) 2020-2022, By Jarut Busarathid and Danai Jedsadathitikul
Updated 2022-01-15