Last active
December 26, 2024 05:29
-
-
Save aallan/ea16d05f7967d8ab899dfff12833a70f to your computer and use it in GitHub Desktop.
Example MicroPython watch code for the RP2040 1.28-inch TFT display watch board
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Digital Watch Face | |
# | |
# Author: Tony Goodhew (28th January 2023) | |
# Updates: Toby Roberts, Andrew Scheller & Alasdair Allan (March 2023) | |
# | |
# Original code taken from https://www.instructables.com/Digital-Watch-Display-MicroPython/ | |
from machine import Pin,I2C,SPI,PWM | |
import framebuf | |
import time | |
import math | |
DC = 8 | |
CS = 9 | |
SCK = 10 | |
MOSI = 11 | |
RST = 12 | |
BL = 13 | |
Vbat_Pin = 29 | |
width = 240 | |
height = 240 | |
class LCD_1inch28(framebuf.FrameBuffer): # Waveshare RP2040 1.28" IPS LCD Board Driver - Round Display | |
def __init__(self): | |
self.width = 240 | |
self.height = 240 | |
self.cs = Pin(CS,Pin.OUT) | |
self.rst = Pin(RST,Pin.OUT) | |
self.cs(1) | |
self.spi = SPI(1,100_000_000,polarity=0, phase=0,sck=Pin(SCK),mosi=Pin(MOSI),miso=None) | |
self.dc = Pin(DC,Pin.OUT) | |
self.dc(1) | |
self.buffer = bytearray(self.height * self.width * 2) | |
super().__init__(self.buffer, self.width, self.height, framebuf.RGB565) | |
self.init_display() | |
self.red = 0x07E0 | |
self.green = 0x001f | |
self.blue = 0xf800 | |
self.white = 0xffff | |
self.fill(self.white) | |
self.show() | |
self.pwm = PWM(Pin(BL)) | |
self.pwm.freq(5000) | |
def write_cmd(self, cmd): | |
self.cs(1) | |
self.dc(0) | |
self.cs(0) | |
self.spi.write(bytearray([cmd])) | |
self.cs(1) | |
def write_data(self, buf): | |
self.cs(1) | |
self.dc(1) | |
self.cs(0) | |
self.spi.write(bytearray([buf])) | |
self.cs(1) | |
def set_bl_pwm(self,duty): | |
self.pwm.duty_u16(duty)#max 65535 | |
def init_display(self): | |
"""Initialize display""" | |
self.rst(1) | |
time.sleep(0.01) | |
self.rst(0) | |
time.sleep(0.01) | |
self.rst(1) | |
time.sleep(0.05) | |
self.write_cmd(0xEF) | |
self.write_cmd(0xEB) | |
self.write_data(0x14) | |
self.write_cmd(0xFE) | |
self.write_cmd(0xEF) | |
self.write_cmd(0xEB) | |
self.write_data(0x14) | |
self.write_cmd(0x84) | |
self.write_data(0x40) | |
self.write_cmd(0x85) | |
self.write_data(0xFF) | |
self.write_cmd(0x86) | |
self.write_data(0xFF) | |
self.write_cmd(0x87) | |
self.write_data(0xFF) | |
self.write_cmd(0x88) | |
self.write_data(0x0A) | |
self.write_cmd(0x89) | |
self.write_data(0x21) | |
self.write_cmd(0x8A) | |
self.write_data(0x00) | |
self.write_cmd(0x8B) | |
self.write_data(0x80) | |
self.write_cmd(0x8C) | |
self.write_data(0x01) | |
self.write_cmd(0x8D) | |
self.write_data(0x01) | |
self.write_cmd(0x8E) | |
self.write_data(0xFF) | |
self.write_cmd(0x8F) | |
self.write_data(0xFF) | |
self.write_cmd(0xB6) | |
self.write_data(0x00) | |
self.write_data(0x20) | |
self.write_cmd(0x36) | |
self.write_data(0x98) | |
self.write_cmd(0x3A) | |
self.write_data(0x05) | |
self.write_cmd(0x90) | |
self.write_data(0x08) | |
self.write_data(0x08) | |
self.write_data(0x08) | |
self.write_data(0x08) | |
self.write_cmd(0xBD) | |
self.write_data(0x06) | |
self.write_cmd(0xBC) | |
self.write_data(0x00) | |
self.write_cmd(0xFF) | |
self.write_data(0x60) | |
self.write_data(0x01) | |
self.write_data(0x04) | |
self.write_cmd(0xC3) | |
self.write_data(0x13) | |
self.write_cmd(0xC4) | |
self.write_data(0x13) | |
self.write_cmd(0xC9) | |
self.write_data(0x22) | |
self.write_cmd(0xBE) | |
self.write_data(0x11) | |
self.write_cmd(0xE1) | |
self.write_data(0x10) | |
self.write_data(0x0E) | |
self.write_cmd(0xDF) | |
self.write_data(0x21) | |
self.write_data(0x0c) | |
self.write_data(0x02) | |
self.write_cmd(0xF0) | |
self.write_data(0x45) | |
self.write_data(0x09) | |
self.write_data(0x08) | |
self.write_data(0x08) | |
self.write_data(0x26) | |
self.write_data(0x2A) | |
self.write_cmd(0xF1) | |
self.write_data(0x43) | |
self.write_data(0x70) | |
self.write_data(0x72) | |
self.write_data(0x36) | |
self.write_data(0x37) | |
self.write_data(0x6F) | |
self.write_cmd(0xF2) | |
self.write_data(0x45) | |
self.write_data(0x09) | |
self.write_data(0x08) | |
self.write_data(0x08) | |
self.write_data(0x26) | |
self.write_data(0x2A) | |
self.write_cmd(0xF3) | |
self.write_data(0x43) | |
self.write_data(0x70) | |
self.write_data(0x72) | |
self.write_data(0x36) | |
self.write_data(0x37) | |
self.write_data(0x6F) | |
self.write_cmd(0xED) | |
self.write_data(0x1B) | |
self.write_data(0x0B) | |
self.write_cmd(0xAE) | |
self.write_data(0x77) | |
self.write_cmd(0xCD) | |
self.write_data(0x63) | |
self.write_cmd(0x70) | |
self.write_data(0x07) | |
self.write_data(0x07) | |
self.write_data(0x04) | |
self.write_data(0x0E) | |
self.write_data(0x0F) | |
self.write_data(0x09) | |
self.write_data(0x07) | |
self.write_data(0x08) | |
self.write_data(0x03) | |
self.write_cmd(0xE8) | |
self.write_data(0x34) | |
self.write_cmd(0x62) | |
self.write_data(0x18) | |
self.write_data(0x0D) | |
self.write_data(0x71) | |
self.write_data(0xED) | |
self.write_data(0x70) | |
self.write_data(0x70) | |
self.write_data(0x18) | |
self.write_data(0x0F) | |
self.write_data(0x71) | |
self.write_data(0xEF) | |
self.write_data(0x70) | |
self.write_data(0x70) | |
self.write_cmd(0x63) | |
self.write_data(0x18) | |
self.write_data(0x11) | |
self.write_data(0x71) | |
self.write_data(0xF1) | |
self.write_data(0x70) | |
self.write_data(0x70) | |
self.write_data(0x18) | |
self.write_data(0x13) | |
self.write_data(0x71) | |
self.write_data(0xF3) | |
self.write_data(0x70) | |
self.write_data(0x70) | |
self.write_cmd(0x64) | |
self.write_data(0x28) | |
self.write_data(0x29) | |
self.write_data(0xF1) | |
self.write_data(0x01) | |
self.write_data(0xF1) | |
self.write_data(0x00) | |
self.write_data(0x07) | |
self.write_cmd(0x66) | |
self.write_data(0x3C) | |
self.write_data(0x00) | |
self.write_data(0xCD) | |
self.write_data(0x67) | |
self.write_data(0x45) | |
self.write_data(0x45) | |
self.write_data(0x10) | |
self.write_data(0x00) | |
self.write_data(0x00) | |
self.write_data(0x00) | |
self.write_cmd(0x67) | |
self.write_data(0x00) | |
self.write_data(0x3C) | |
self.write_data(0x00) | |
self.write_data(0x00) | |
self.write_data(0x00) | |
self.write_data(0x01) | |
self.write_data(0x54) | |
self.write_data(0x10) | |
self.write_data(0x32) | |
self.write_data(0x98) | |
self.write_cmd(0x74) | |
self.write_data(0x10) | |
self.write_data(0x85) | |
self.write_data(0x80) | |
self.write_data(0x00) | |
self.write_data(0x00) | |
self.write_data(0x4E) | |
self.write_data(0x00) | |
self.write_cmd(0x98) | |
self.write_data(0x3e) | |
self.write_data(0x07) | |
self.write_cmd(0x35) | |
self.write_cmd(0x21) | |
self.write_cmd(0x11) | |
time.sleep(0.12) | |
self.write_cmd(0x29) | |
time.sleep(0.02) | |
self.write_cmd(0x21) | |
self.write_cmd(0x11) | |
self.write_cmd(0x29) | |
self.write_cmd(0x36) | |
self.write_data(0x68) | |
def show(self): | |
self.write_cmd(0x2A) | |
self.write_data(0x00) | |
self.write_data(0x00) | |
self.write_data(0x00) | |
self.write_data(0xef) | |
self.write_cmd(0x2B) | |
self.write_data(0x00) | |
self.write_data(0x00) | |
self.write_data(0x00) | |
self.write_data(0xEF) | |
self.write_cmd(0x2C) | |
self.cs(1) | |
self.dc(1) | |
self.cs(0) | |
self.spi.write(self.buffer) | |
self.cs(1) | |
class QMI8658(object): | |
def __init__(self,address=0X6B): | |
self._address = address | |
self._bus = I2C(id=1,scl=Pin(I2C_SDL),sda=Pin(I2C_SDA),freq=100_000) | |
bRet=self.WhoAmI() | |
if bRet : | |
self.Read_Revision() | |
else : | |
return NULL | |
self.Config_apply() | |
def _read_byte(self,cmd): | |
rec=self._bus.readfrom_mem(int(self._address),int(cmd),1) | |
return rec[0] | |
def _read_block(self, reg, length=1): | |
rec=self._bus.readfrom_mem(int(self._address),int(reg),length) | |
return rec | |
def _read_u16(self,cmd): | |
LSB = self._bus.readfrom_mem(int(self._address),int(cmd),1) | |
MSB = self._bus.readfrom_mem(int(self._address),int(cmd)+1,1) | |
return (MSB[0] << 8) + LSB[0] | |
def _write_byte(self,cmd,val): | |
self._bus.writeto_mem(int(self._address),int(cmd),bytes([int(val)])) | |
def WhoAmI(self): | |
bRet=False | |
if (0x05) == self._read_byte(0x00): | |
bRet = True | |
return bRet | |
def Read_Revision(self): | |
return self._read_byte(0x01) | |
def Config_apply(self): | |
# REG CTRL1 | |
self._write_byte(0x02,0x60) | |
# REG CTRL2 : QMI8658AccRange_8g and QMI8658AccOdr_1000Hz | |
self._write_byte(0x03,0x23) | |
# REG CTRL3 : QMI8658GyrRange_512dps and QMI8658GyrOdr_1000Hz | |
self._write_byte(0x04,0x53) | |
# REG CTRL4 : No | |
self._write_byte(0x05,0x00) | |
# REG CTRL5 : Enable Gyroscope And Accelerometer Low-Pass Filter | |
self._write_byte(0x06,0x11) | |
# REG CTRL6 : Disables Motion on Demand. | |
self._write_byte(0x07,0x00) | |
# REG CTRL7 : Enable Gyroscope And Accelerometer | |
self._write_byte(0x08,0x03) | |
def Read_Raw_XYZ(self): | |
xyz=[0,0,0,0,0,0] | |
raw_timestamp = self._read_block(0x30,3) | |
raw_acc_xyz=self._read_block(0x35,6) | |
raw_gyro_xyz=self._read_block(0x3b,6) | |
raw_xyz=self._read_block(0x35,12) | |
timestamp = (raw_timestamp[2]<<16)|(raw_timestamp[1]<<8)|(raw_timestamp[0]) | |
for i in range(6): | |
# xyz[i]=(raw_acc_xyz[(i*2)+1]<<8)|(raw_acc_xyz[i*2]) | |
# xyz[i+3]=(raw_gyro_xyz[((i+3)*2)+1]<<8)|(raw_gyro_xyz[(i+3)*2]) | |
xyz[i] = (raw_xyz[(i*2)+1]<<8)|(raw_xyz[i*2]) | |
if xyz[i] >= 32767: | |
xyz[i] = xyz[i]-65535 | |
return xyz | |
def Read_XYZ(self): | |
xyz=[0,0,0,0,0,0] | |
raw_xyz=self.Read_Raw_XYZ() | |
#QMI8658AccRange_8g | |
acc_lsb_div=(1<<12) | |
#QMI8658GyrRange_512dps | |
gyro_lsb_div = 64 | |
for i in range(3): | |
xyz[i]=raw_xyz[i]/acc_lsb_div#(acc_lsb_div/1000.0) | |
xyz[i+3]=raw_xyz[i+3]*1.0/gyro_lsb_div | |
return xyz | |
def colour(R,G,B): # Convert RGB888 to RGB565 | |
return (((G&0b00011100)<<3) +((B&0b11111000)>>3)<<8) + (R&0b11111000)+((G&0b11100000)>>5) | |
LCD = LCD_1inch28() #=============== Initialise the display =================== | |
LCD.set_bl_pwm(65535) # Brightness | |
#qmi8658=QMI8658() # Initialise gyro accl | |
#Vbat= ADC(Pin(Vbat_Pin)) # Lipo voltage pin | |
# ========== Start of Triangles code ============= | |
# Modified from https://github.com/SpiderMaf/PiPicoDsply/blob/main/filled-triangles.py | |
# To work on WaveShare Pi Pico displays | |
# ========== Version 2 FIXED ! 23 May 2022 ========== | |
class Point: | |
def __init__(self,x,y): | |
self.X=x | |
self.Y=y | |
def __str__(self): | |
return "Point(%s,%s)"%(self.X,self.Y) | |
class Triangle: | |
def __init__(self,p1,p2,p3): | |
self.P1=p1 | |
self.P2=p2 | |
self.P3=p3 | |
def __str__(self): | |
return "Triangle(%s,%s,%s)"%(self.P1,self.P2,self.P3) | |
def draw(self): | |
print("I should draw now") | |
self.fillTri() | |
# Filled triangle routines ported from http://www.sunshine2k.de/coding/java/TriangleRasterization/TriangleRasterization.html | |
def sortVerticesAscendingByY(self): | |
if self.P1.Y > self.P2.Y: | |
vTmp = self.P1 | |
self.P1 = self.P2 | |
self.P2 = vTmp | |
if self.P1.Y > self.P3.Y: | |
vTmp = self.P1 | |
self.P1 = self.P3 | |
self.P3 = vTmp | |
if self.P2.Y > self.P3.Y: | |
vTmp = self.P2 | |
self.P2 = self.P3 | |
self.P3 = vTmp | |
def fillTri(self): | |
self.sortVerticesAscendingByY() | |
if self.P2.Y == self.P3.Y: | |
fillBottomFlatTriangle(self.P1, self.P2, self.P3) | |
else: | |
if self.P1.Y == self.P2.Y: | |
fillTopFlatTriangle(self.P1, self.P2, self.P3) | |
else: | |
newx = int(self.P1.X + (float(self.P2.Y - self.P1.Y) / float(self.P3.Y - self.P1.Y)) * (self.P3.X - self.P1.X)) | |
newy = self.P2.Y | |
pTmp = Point( newx,newy ) | |
# print(pTmp) | |
fillBottomFlatTriangle(self.P1, self.P2, pTmp) | |
fillTopFlatTriangle(self.P2, pTmp, self.P3) | |
def fillBottomFlatTriangle(p1,p2,p3): | |
# print("BF",p1,p2,p3) | |
if p2.Y > p3.Y: | |
ty = p3.Y | |
p3.Y = p2.Y | |
p2.Y = ty | |
tx = p3.X | |
p3.X = p2.X | |
p2.X = tx | |
print(p1,p2,p3) | |
slope1 = float(p2.X - p1.X) / float (p2.Y - p1.Y) | |
slope2 = float(p3.X - p1.X) / float (p3.Y - p1.Y) | |
x1 = p1.X | |
x2 = p1.X + 0.5 | |
# print("B",p1.Y,p2.Y) | |
for scanlineY in range(p1.Y,p2.Y): | |
# print(scanlineY) | |
# LCD.pixel_span(int(x1), scanlineY, int(x2)-int(x1)) # Switch pixel_span() to hline() / Pimoroni to WS | |
LCD.hline(int(x1),scanlineY, int(x2)-int(x1),c) | |
LCD.hline(int(x2),scanlineY, -(int(x2)-int(x1)),c) | |
# LCD.show() # Here and below | |
# utime.sleep(0.1) # <===== Uncomment to see how graphic elements are drawn | |
x1 += slope1 | |
x2 += slope2 | |
# LCD.show() # LCD.show() and utime.sleep(0.1) | |
def fillTopFlatTriangle(p1,p2,p3): | |
# print("TF",p1,p2,p3) | |
slope1 = float(p3.X - p1.X) / float(p3.Y - p1.Y) | |
slope2 = float(p3.X - p2.X) / float(p3.Y - p2.Y) | |
x1 = p3.X | |
x2 = p3.X + 0.5 | |
# print("T",p3.Y,p1.Y-1) | |
for scanlineY in range (p3.Y,p1.Y-1,-1): | |
# print(scanlineY) | |
# LCD.pixel_span(int(x1), scanlineY, int(x2)-int(x1)) # Switch pixel_span() to hline() / Pimoroni to WS | |
LCD.hline(int(x1),scanlineY, int(x2)-int(x1)+1,c) | |
LCD.hline(int(x2),scanlineY, -(int(x2)-int(x1)-1),c) | |
# LCD.show() | |
# utime.sleep(0.1) | |
x1 -= slope1 | |
x2 -= slope2 | |
# LCD.show() | |
# ============== End of Triangles Code =============== | |
# =========== New GFX Routines ============ | |
def clear(c): | |
LCD.fill(c) | |
def triangle(x1,y1,x2,y2,x3,y3,c): # Draw outline triangle | |
LCD.line(x1,y1,x2,y2,c) | |
LCD.line(x2,y2,x3,y3,c) | |
LCD.line(x3,y3,x1,y1,c) | |
def tri_filled(x1,y1,x2,y2,x3,y3,c): # Draw filled triangle | |
t=Triangle(Point(x1,y1),Point(x2,y2),Point(x3,y3)) # Define corners | |
t.fillTri() # Call main code block | |
def circle(x,y,r,c): | |
LCD.hline(x-r,y,r*2,c) | |
for i in range(1,r): | |
a = int(math.sqrt(r*r-i*i)) # Pythagoras! | |
LCD.hline(x-a,y+i,a*2,c) # Lower half | |
LCD.hline(x-a,y-i,a*2,c) # Upper half | |
def ring(x,y,r,c): | |
LCD.pixel(x-r,y,c) | |
LCD.pixel(x+r,y,c) | |
LCD.pixel(x,y-r,c) | |
LCD.pixel(x,y+r,c) | |
for i in range(1,r): | |
a = int(math.sqrt(r*r-i*i)) | |
LCD.pixel(x-a,y-i,c) | |
LCD.pixel(x+a,y-i,c) | |
LCD.pixel(x-a,y+i,c) | |
LCD.pixel(x+a,y+i,c) | |
LCD.pixel(x-i,y-a,c) | |
LCD.pixel(x+i,y-a,c) | |
LCD.pixel(x-i,y+a,c) | |
LCD.pixel(x+i,y+a,c) | |
# ===========Start of FONTS Section========================= | |
# Standard ASCII 5x8 font | |
# https://gist.github.com/tdicola/229b3eeddc12d58fb0bc724a9062aa05 | |
FONT_HEIGHT = 8 | |
FONT_WIDTH = 5 | |
FONT = bytes([ | |
0x00, 0x00, 0x00, 0x00, 0x00, # <space> | |
0x3E, 0x5B, 0x4F, 0x5B, 0x3E, | |
0x3E, 0x6B, 0x4F, 0x6B, 0x3E, | |
0x1C, 0x3E, 0x7C, 0x3E, 0x1C, | |
0x18, 0x3C, 0x7E, 0x3C, 0x18, | |
0x1C, 0x57, 0x7D, 0x57, 0x1C, | |
0x1C, 0x5E, 0x7F, 0x5E, 0x1C, | |
0x00, 0x18, 0x3C, 0x18, 0x00, | |
0xFF, 0xE7, 0xC3, 0xE7, 0xFF, | |
0x00, 0x18, 0x24, 0x18, 0x00, | |
0xFF, 0xE7, 0xDB, 0xE7, 0xFF, | |
0x30, 0x48, 0x3A, 0x06, 0x0E, | |
0x26, 0x29, 0x79, 0x29, 0x26, | |
0x40, 0x7F, 0x05, 0x05, 0x07, | |
0x40, 0x7F, 0x05, 0x25, 0x3F, | |
0x5A, 0x3C, 0xE7, 0x3C, 0x5A, | |
0x7F, 0x3E, 0x1C, 0x1C, 0x08, | |
0x08, 0x1C, 0x1C, 0x3E, 0x7F, | |
0x14, 0x22, 0x7F, 0x22, 0x14, | |
0x5F, 0x5F, 0x00, 0x5F, 0x5F, | |
0x06, 0x09, 0x7F, 0x01, 0x7F, | |
0x00, 0x66, 0x89, 0x95, 0x6A, | |
0x60, 0x60, 0x60, 0x60, 0x60, | |
0x94, 0xA2, 0xFF, 0xA2, 0x94, | |
0x08, 0x04, 0x7E, 0x04, 0x08, # UP | |
0x10, 0x20, 0x7E, 0x20, 0x10, # Down | |
0x08, 0x08, 0x2A, 0x1C, 0x08, # Right | |
0x08, 0x1C, 0x2A, 0x08, 0x08, # Left | |
0x1E, 0x10, 0x10, 0x10, 0x10, | |
0x0C, 0x1E, 0x0C, 0x1E, 0x0C, | |
0x30, 0x38, 0x3E, 0x38, 0x30, | |
0x06, 0x0E, 0x3E, 0x0E, 0x06, | |
0x00, 0x00, 0x00, 0x00, 0x00, | |
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, 0x56, 0x20, 0x50, | |
0x00, 0x08, 0x07, 0x03, 0x00, | |
0x00, 0x1C, 0x22, 0x41, 0x00, | |
0x00, 0x41, 0x22, 0x1C, 0x00, | |
0x2A, 0x1C, 0x7F, 0x1C, 0x2A, | |
0x08, 0x08, 0x3E, 0x08, 0x08, | |
0x00, 0x80, 0x70, 0x30, 0x00, | |
0x08, 0x08, 0x08, 0x08, 0x08, | |
0x00, 0x00, 0x60, 0x60, 0x00, | |
0x20, 0x10, 0x08, 0x04, 0x02, | |
0x3E, 0x51, 0x49, 0x45, 0x3E, | |
0x00, 0x42, 0x7F, 0x40, 0x00, | |
0x72, 0x49, 0x49, 0x49, 0x46, | |
0x21, 0x41, 0x49, 0x4D, 0x33, | |
0x18, 0x14, 0x12, 0x7F, 0x10, | |
0x27, 0x45, 0x45, 0x45, 0x39, | |
0x3C, 0x4A, 0x49, 0x49, 0x31, | |
0x41, 0x21, 0x11, 0x09, 0x07, | |
0x36, 0x49, 0x49, 0x49, 0x36, | |
0x46, 0x49, 0x49, 0x29, 0x1E, | |
0x00, 0x00, 0x14, 0x00, 0x00, | |
0x00, 0x40, 0x34, 0x00, 0x00, | |
0x00, 0x08, 0x14, 0x22, 0x41, | |
0x14, 0x14, 0x14, 0x14, 0x14, | |
0x00, 0x41, 0x22, 0x14, 0x08, | |
0x02, 0x01, 0x59, 0x09, 0x06, | |
0x3E, 0x41, 0x5D, 0x59, 0x4E, | |
0x7C, 0x12, 0x11, 0x12, 0x7C, # A | |
0x7F, 0x49, 0x49, 0x49, 0x36, | |
0x3E, 0x41, 0x41, 0x41, 0x22, | |
0x7F, 0x41, 0x41, 0x41, 0x3E, | |
0x7F, 0x49, 0x49, 0x49, 0x41, | |
0x7F, 0x09, 0x09, 0x09, 0x01, | |
0x3E, 0x41, 0x41, 0x51, 0x73, | |
0x7F, 0x08, 0x08, 0x08, 0x7F, | |
0x00, 0x41, 0x7F, 0x41, 0x00, | |
0x20, 0x40, 0x41, 0x3F, 0x01, | |
0x7F, 0x08, 0x14, 0x22, 0x41, | |
0x7F, 0x40, 0x40, 0x40, 0x40, | |
0x7F, 0x02, 0x1C, 0x02, 0x7F, | |
0x7F, 0x04, 0x08, 0x10, 0x7F, | |
0x3E, 0x41, 0x41, 0x41, 0x3E, | |
0x7F, 0x09, 0x09, 0x09, 0x06, | |
0x3E, 0x41, 0x51, 0x21, 0x5E, | |
0x7F, 0x09, 0x19, 0x29, 0x46, | |
0x26, 0x49, 0x49, 0x49, 0x32, | |
0x03, 0x01, 0x7F, 0x01, 0x03, | |
0x3F, 0x40, 0x40, 0x40, 0x3F, | |
0x1F, 0x20, 0x40, 0x20, 0x1F, | |
0x3F, 0x40, 0x38, 0x40, 0x3F, | |
0x63, 0x14, 0x08, 0x14, 0x63, | |
0x03, 0x04, 0x78, 0x04, 0x03, | |
0x61, 0x59, 0x49, 0x4D, 0x43, | |
0x00, 0x7F, 0x41, 0x41, 0x41, | |
0x02, 0x04, 0x08, 0x10, 0x20, | |
0x00, 0x41, 0x41, 0x41, 0x7F, | |
0x04, 0x02, 0x01, 0x02, 0x04, | |
0x40, 0x40, 0x40, 0x40, 0x40, | |
0x00, 0x03, 0x07, 0x08, 0x00, | |
0x20, 0x54, 0x54, 0x78, 0x40, | |
0x7F, 0x28, 0x44, 0x44, 0x38, | |
0x38, 0x44, 0x44, 0x44, 0x28, | |
0x38, 0x44, 0x44, 0x28, 0x7F, | |
0x38, 0x54, 0x54, 0x54, 0x18, | |
0x00, 0x08, 0x7E, 0x09, 0x02, | |
0x18, 0xA4, 0xA4, 0x9C, 0x78, | |
0x7F, 0x08, 0x04, 0x04, 0x78, | |
0x00, 0x44, 0x7D, 0x40, 0x00, | |
0x20, 0x40, 0x40, 0x3D, 0x00, | |
0x7F, 0x10, 0x28, 0x44, 0x00, | |
0x00, 0x41, 0x7F, 0x40, 0x00, | |
0x7C, 0x04, 0x78, 0x04, 0x78, | |
0x7C, 0x08, 0x04, 0x04, 0x78, | |
0x38, 0x44, 0x44, 0x44, 0x38, | |
0xFC, 0x18, 0x24, 0x24, 0x18, | |
0x18, 0x24, 0x24, 0x18, 0xFC, | |
0x7C, 0x08, 0x04, 0x04, 0x08, | |
0x48, 0x54, 0x54, 0x54, 0x24, | |
0x04, 0x04, 0x3F, 0x44, 0x24, | |
0x3C, 0x40, 0x40, 0x20, 0x7C, | |
0x1C, 0x20, 0x40, 0x20, 0x1C, | |
0x3C, 0x40, 0x30, 0x40, 0x3C, | |
0x44, 0x28, 0x10, 0x28, 0x44, | |
0x4C, 0x90, 0x90, 0x90, 0x7C, | |
0x44, 0x64, 0x54, 0x4C, 0x44, | |
0x00, 0x08, 0x36, 0x41, 0x00, | |
0x00, 0x00, 0x77, 0x00, 0x00, | |
0x00, 0x41, 0x36, 0x08, 0x00, | |
0x02, 0x01, 0x02, 0x04, 0x02, | |
0x3C, 0x26, 0x23, 0x26, 0x3C, | |
0x1E, 0xA1, 0xA1, 0x61, 0x12, # Extension starts here | |
0x3A, 0x40, 0x40, 0x20, 0x7A, | |
0x38, 0x54, 0x54, 0x55, 0x59, | |
0x21, 0x55, 0x55, 0x79, 0x41, | |
0x22, 0x54, 0x54, 0x78, 0x42, # a-umlaut | |
0x21, 0x55, 0x54, 0x78, 0x40, | |
0x20, 0x54, 0x55, 0x79, 0x40, | |
0x0C, 0x1E, 0x52, 0x72, 0x12, | |
0x39, 0x55, 0x55, 0x55, 0x59, | |
0x39, 0x54, 0x54, 0x54, 0x59, | |
0x39, 0x55, 0x54, 0x54, 0x58, | |
0x00, 0x00, 0x45, 0x7C, 0x41, | |
0x00, 0x02, 0x45, 0x7D, 0x42, | |
0x00, 0x01, 0x45, 0x7C, 0x40, | |
0x7D, 0x12, 0x11, 0x12, 0x7D, # A-umlaut | |
0xF0, 0x28, 0x25, 0x28, 0xF0, | |
0x7C, 0x54, 0x55, 0x45, 0x00, | |
0x20, 0x54, 0x54, 0x7C, 0x54, | |
0x7C, 0x0A, 0x09, 0x7F, 0x49, | |
0x32, 0x49, 0x49, 0x49, 0x32, | |
0x3A, 0x44, 0x44, 0x44, 0x3A, # o-umlaut | |
0x32, 0x4A, 0x48, 0x48, 0x30, | |
0x3A, 0x41, 0x41, 0x21, 0x7A, | |
0x3A, 0x42, 0x40, 0x20, 0x78, | |
0x00, 0x9D, 0xA0, 0xA0, 0x7D, | |
0x3D, 0x42, 0x42, 0x42, 0x3D, # O-umlaut | |
0x3D, 0x40, 0x40, 0x40, 0x3D, | |
0x3C, 0x24, 0xFF, 0x24, 0x24, | |
0x48, 0x7E, 0x49, 0x43, 0x66, | |
0x2B, 0x2F, 0xFC, 0x2F, 0x2B, | |
0xFF, 0x09, 0x29, 0xF6, 0x20, | |
0xC0, 0x88, 0x7E, 0x09, 0x03, | |
0x20, 0x54, 0x54, 0x79, 0x41, | |
0x00, 0x00, 0x44, 0x7D, 0x41, | |
0x30, 0x48, 0x48, 0x4A, 0x32, | |
0x38, 0x40, 0x40, 0x22, 0x7A, | |
0x00, 0x7A, 0x0A, 0x0A, 0x72, | |
0x7D, 0x0D, 0x19, 0x31, 0x7D, | |
0x26, 0x29, 0x29, 0x2F, 0x28, | |
0x26, 0x29, 0x29, 0x29, 0x26, | |
0x30, 0x48, 0x4D, 0x40, 0x20, | |
0x38, 0x08, 0x08, 0x08, 0x08, | |
0x08, 0x08, 0x08, 0x08, 0x38, | |
0x2F, 0x10, 0xC8, 0xAC, 0xBA, | |
0x2F, 0x10, 0x28, 0x34, 0xFA, | |
0x00, 0x00, 0x7B, 0x00, 0x00, | |
0x08, 0x14, 0x2A, 0x14, 0x22, | |
0x22, 0x14, 0x2A, 0x14, 0x08, | |
0x55, 0x00, 0x55, 0x00, 0x55, # 176 (25% block) missing in old code | |
0xAA, 0x55, 0xAA, 0x55, 0xAA, # 50% block | |
0xFF, 0x55, 0xFF, 0x55, 0xFF, # 75% block | |
0x00, 0x00, 0x00, 0xFF, 0x00, | |
0x10, 0x10, 0x10, 0xFF, 0x00, | |
0x14, 0x14, 0x14, 0xFF, 0x00, | |
0x10, 0x10, 0xFF, 0x00, 0xFF, | |
0x10, 0x10, 0xF0, 0x10, 0xF0, | |
0x14, 0x14, 0x14, 0xFC, 0x00, | |
0x14, 0x14, 0xF7, 0x00, 0xFF, | |
0x00, 0x00, 0xFF, 0x00, 0xFF, | |
0x14, 0x14, 0xF4, 0x04, 0xFC, | |
0x14, 0x14, 0x17, 0x10, 0x1F, | |
0x10, 0x10, 0x1F, 0x10, 0x1F, | |
0x14, 0x14, 0x14, 0x1F, 0x00, | |
0x10, 0x10, 0x10, 0xF0, 0x00, | |
0x00, 0x00, 0x00, 0x1F, 0x10, | |
0x10, 0x10, 0x10, 0x1F, 0x10, | |
0x10, 0x10, 0x10, 0xF0, 0x10, | |
0x00, 0x00, 0x00, 0xFF, 0x10, | |
0x10, 0x10, 0x10, 0x10, 0x10, | |
0x10, 0x10, 0x10, 0xFF, 0x10, | |
0x00, 0x00, 0x00, 0xFF, 0x14, | |
0x00, 0x00, 0xFF, 0x00, 0xFF, | |
0x00, 0x00, 0x1F, 0x10, 0x17, | |
0x00, 0x00, 0xFC, 0x04, 0xF4, | |
0x14, 0x14, 0x17, 0x10, 0x17, | |
0x14, 0x14, 0xF4, 0x04, 0xF4, | |
0x00, 0x00, 0xFF, 0x00, 0xF7, | |
0x14, 0x14, 0x14, 0x14, 0x14, | |
0x14, 0x14, 0xF7, 0x00, 0xF7, | |
0x14, 0x14, 0x14, 0x17, 0x14, | |
0x10, 0x10, 0x1F, 0x10, 0x1F, | |
0x14, 0x14, 0x14, 0xF4, 0x14, | |
0x10, 0x10, 0xF0, 0x10, 0xF0, | |
0x00, 0x00, 0x1F, 0x10, 0x1F, | |
0x00, 0x00, 0x00, 0x1F, 0x14, | |
0x00, 0x00, 0x00, 0xFC, 0x14, | |
0x00, 0x00, 0xF0, 0x10, 0xF0, | |
0x10, 0x10, 0xFF, 0x10, 0xFF, | |
0x14, 0x14, 0x14, 0xFF, 0x14, | |
0x10, 0x10, 0x10, 0x1F, 0x00, | |
0x00, 0x00, 0x00, 0xF0, 0x10, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
0xF0, 0xF0, 0xF0, 0xF0, 0xF0, | |
0xFF, 0xFF, 0xFF, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0xFF, 0xFF, | |
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, | |
0x38, 0x44, 0x44, 0x38, 0x44, # alpha - Greek characters start here at 224 | |
0xFC, 0x4A, 0x4A, 0x4A, 0x34, # sharp-s or beta | |
0x7E, 0x02, 0x02, 0x06, 0x06, | |
0x02, 0x7E, 0x02, 0x7E, 0x02, # pi | |
0x63, 0x55, 0x49, 0x41, 0x63, | |
0x38, 0x44, 0x44, 0x3C, 0x04, | |
0x40, 0x7E, 0x20, 0x1E, 0x20, # mu | |
0x06, 0x02, 0x7E, 0x02, 0x02, | |
0x99, 0xA5, 0xE7, 0xA5, 0x99, | |
0x1C, 0x2A, 0x49, 0x2A, 0x1C, | |
0x4C, 0x72, 0x01, 0x72, 0x4C, # omega | |
0x30, 0x4A, 0x4D, 0x4D, 0x30, | |
0x30, 0x48, 0x78, 0x48, 0x30, | |
0xBC, 0x62, 0x5A, 0x46, 0x3D, | |
0x3E, 0x49, 0x49, 0x49, 0x00, | |
0x7E, 0x01, 0x01, 0x01, 0x7E, # End of Greek chars | |
0x2A, 0x2A, 0x2A, 0x2A, 0x2A, # equivalent to 240 | |
0x44, 0x44, 0x5F, 0x44, 0x44, # + or - | |
0x40, 0x51, 0x4A, 0x44, 0x40, # >= | |
0x40, 0x44, 0x4A, 0x51, 0x40, # <= | |
0x00, 0x00, 0xFF, 0x01, 0x03, # top of integral | |
0xE0, 0x80, 0xFF, 0x00, 0x00, # bottom of integral | |
0x08, 0x08, 0x6B, 0x6B, 0x08, | |
0x36, 0x12, 0x36, 0x24, 0x36, # approximately | |
0x06, 0x0F, 0x09, 0x0F, 0x06, # Degree | |
0x00, 0x00, 0x18, 0x18, 0x00, | |
0x00, 0x00, 0x10, 0x10, 0x00, | |
0x30, 0x40, 0xFF, 0x01, 0x01, # sq root | |
0x00, 0x1F, 0x01, 0x01, 0x1E, # n superscript | |
0x00, 0x19, 0x1D, 0x17, 0x12, # squared (^2) | |
0x00, 0x3C, 0x3C, 0x3C, 0x3C, | |
0x00, 0x00, 0x00, 0x00, 0x00 # 255 also a <space> | |
]) | |
def character(asc,xt,yt,sz,r,g,b): # Single character sz is size: 1 or 2 | |
cc = colour(r,g,b) | |
code = asc * 5 # 5 bytes per character | |
for ii in range(5): | |
line = FONT[code + ii] | |
for yy in range(8): | |
if (line >> yy) & 0x1: | |
LCD.pixel(ii*sz+xt,yy*sz+yt,cc) | |
if sz > 1: | |
LCD.pixel(ii*sz+xt+1,yy*sz+yt,cc) | |
LCD.pixel(ii*sz+xt,yy*sz+yt+1,cc) | |
LCD.pixel(ii*sz+xt+1,yy*sz+yt+1,cc) | |
if sz == 3: | |
LCD.pixel(ii*sz+xt, yy*sz+yt+2,cc) | |
LCD.pixel(ii*sz+xt+1,yy*sz+yt+2,cc) | |
LCD.pixel(ii*sz+xt+2,yy*sz+yt+2,cc) | |
LCD.pixel(ii*sz+xt+2,yy*sz+yt,cc) | |
LCD.pixel(ii*sz+xt+2,yy*sz+yt+1,cc) | |
def prnt_st(asci,xx,yy,sz,r,g,b): # Text string | |
if sz == 1: move = 6 | |
if sz == 2: move = 11 | |
if sz == 3: move = 17 | |
for letter in(asci): | |
asci = ord(letter) | |
character(asci,xx,yy,sz,r,g,b) | |
xx = xx + move | |
def cntr_st(s,y,sz,r,g,b): # Centres text on line y | |
if sz == 1: w = 6 | |
if sz == 2: w = 11 | |
if sz == 3: w = 17 | |
gap = int((width - len(s) * w)/2) | |
prnt_st(s,gap,y,sz,r,g,b) | |
# =========== End of font support routines =========== | |
# ==== Board now setup ========== MAIN BELOW==================== | |
def end_point(theta, rr): # Calculate end of hand offsets | |
theta_rad = math.radians(theta) | |
theta_rad = math.radians(theta) | |
xx = int(rr * math.sin(theta_rad)) | |
yy = -int(rr * math.cos(theta_rad)) | |
return xx,yy | |
# https://youtu.be/X6PRcno_WbQ | |
clear(0) # Clear the screen | |
xc = 120 # Coordinates of centre | |
yc = 120 | |
circle(xc,yc,120,colour(255,0,0)) # Large red circle | |
r = 120 # Tick outer radius - longer radius to stick out by 2 pixels | |
# Draw the scale ticks - lines from centre | |
for p in range(0,360,6): | |
hxn, hyn = end_point(p, r) | |
LCD.line(120,120,120+hxn,120+hyn,colour(255,255,255)) | |
# Clear centre leaving blue ring with white ticks | |
circle(xc,yc,110,colour(0,0,0)) | |
r = 120 # Tick outer radius - longer radius to stick out by 2 pixels | |
# Draw the scale ticks - lines from centre | |
for p in range(0,360,30): | |
hxn, hyn = end_point(p, r) | |
LCD.line(120,120,120+hxn,120+hyn,colour(255,255,255)) | |
# Clear centre leaving blue ring with white ticks | |
circle(xc,yc,100,colour(0,0,0)) | |
mr = 100 # length of minite hand | |
hr = 70 # length of hour hand | |
sr = 100 # length of second hand | |
# Start time | |
h = 16 | |
m = 28 | |
s = 00 | |
# === Main loop === | |
while True: | |
s = s + 1 # Add a second | |
if s == 60: # Adjust secs, mins and hours as necessary | |
s = 0 | |
m = m + 1 | |
if m == 60: | |
m = 0 | |
h = h + 1 | |
if h == 12: | |
h = 0 | |
# Calculate coordinates of end of second pointer | |
alpha = (s*6) | |
sxn, syn = end_point(alpha, sr) | |
# Calculate coordinates of end of hour pointer | |
alpha = (h*60+m)*360/720 | |
hxn, hyn = end_point(alpha, hr) | |
# Calculate coordinates of end of minute pointer | |
alpha = m * 360/60 | |
mxn, myn = end_point(alpha, sr) | |
# Clear centre circle | |
circle(xc,yc,102,colour(0,0,0)) | |
# Write Title and Scale values | |
cntr_st("Raspberry Pi",68,1,255,255,255) # Message | |
cntr_st("RP2040",88,1,255,255,255) | |
prnt_st("7",70,186,2,0,255,0) | |
prnt_st("5",158,186,2,0,255,0) | |
prnt_st("8",42,160,2,0,255,0) | |
prnt_st("4",190,160,2,0,255,0) | |
prnt_st("9",29,115,2,0,255,0) | |
prnt_st("3",200,115,2,0,255,0) | |
prnt_st("10",40,70,2,0,255,0) | |
prnt_st("2",190,70,2,0,255,0) | |
prnt_st("11",70,35,2,0,255,0) | |
prnt_st("1",157,35,2,0,255,0) | |
prnt_st("12",110,25,2,0,255,0) | |
prnt_st("6",115,200,2,0,255,0) | |
# Draw Digital Time | |
hs = "0"+str(h) | |
ms = "0"+str(m) | |
ts = hs[-2:] +":"+ms[-2:] | |
cntr_st(ts,145,3,255,255,0) | |
# Draw HOUR in red | |
hxnsm = int(hxn/8) | |
hynsm = int(hyn/8) | |
c = colour(255,0,0) | |
tri_filled(120+hxn, 120+hyn, 120+hynsm, 120-hxnsm, 120-hynsm, 120+hxnsm,c) | |
circle(xc,yc,9,colour(255,0,0)) | |
# Draw MINUTE in red | |
mxnsm = int(mxn/15) | |
mynsm = int(myn/15) | |
c = colour(255,0,0) | |
tri_filled(120+mxn, 120+myn, 120+mynsm, 120-mxnsm, 120-mynsm, 120+mxnsm,c) | |
circle(xc,yc,8,colour(0,0,255)) | |
# Draw second hand in white | |
c = colour(255,255,255) | |
LCD.line(xc,yc,120+sxn,120+syn,c) | |
LCD.show() # Update screen | |
# time.sleep(0.05) # Short delay | |
time.sleep(0.9) # sleep for a second! |
Hello Alisdair,
Thanks for posting the project. I noticed on line 348 of this watch_code.py what I believe is a typo:
self._bus = I2C(id=1,scl=Pin(I2C_SDL),sda=Pin(I2C_SDA),freq=100_000)
specifically
scl=Pin(I2C_SDL)
I believe the "I2C_SDL" should be "I2C_SCL".
I hope this helps. Please let me know if this is incorrect.
Respectfully,
John
is it possible to describe how you rotate the screen?
Thank you very much!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi Alisdair,
firstly, thanks for sharing your code.
A couple of things I noticed:
lines 901-904, setting the time was not obvious, maybe move it to the initializations before the LCD class.
then in the Main Loop, the Hours are checked (line 915) and reset to Zero if they reach 12, but obviously not if you start the time at 16:28, they just go on for ever, making no allowance for 24hr time.
If I was more familiar with Github and Gist, I'd try doing an edit and a pull request.
Dave