In this exercise, Raspberry Pi/Python3 act as socket server, ESP32/MicroPython
act as client connect to server via WiFi TCP. Once received, server
(Pi/Python) send a image (240x240) to client (ESP32/MicroPython), then the
client display the image on a 240*240 IPS (ST7789 SPI) LCD.
To make it more flexible, the image is in 240 batch of 240 pixel x 3 color (r,
g, b).
protocol:
Server | | Client
(Raspberry Pi/Python) | | (ESP32/MicroPython)
| |
Start | | Reset
| |
Setup as | |
socketserver.TCPServer | |
| |
| | Join the WiFi network
| | Connect to server with socket
| |
|<-- ACK ---| send ACK
send the 0th line |---------->| display the 0th line
|<-- ACK ---| send ACK
send the 1st line |---------->| display the 1st line
.
.
.
send the 239th line |---------->| display the 239th line
|<-- ACK ---| send ACK
close socket | | close socket
| |
wait next | | bye
pyMyTCP_ImgServer_20210324c.py, Python3 code run on Raspberry Pi.
import socketserver
import platform
import matplotlib.image as mpimg
imageFile = '/home/pi/Desktop/image.jpg'
print("sys info:")
for info in platform.uname():
print(info)
class MyTCPHandler(socketserver.BaseRequestHandler):
#wait client response in 3 byte len
def wait_RESPONSE(self, client):
client.settimeout(10)
res = str()
data = client.recv(4)
return data.decode("utf-8")
def handle(self):
msocket = self.request
print("{} connected:".format(self.client_address[0]))
imgArray = mpimg.imread(imageFile)
self.wait_RESPONSE(msocket) #dummy assume 'ACK' received
print('first RESPONSE received')
for j in range(240):
b = bytes(imgArray[j])
msocket.sendall(bytes(b))
self.wait_RESPONSE(msocket) #dummy assume 'ACK' received
print('image sent finished')
msocket.close()
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
# Create the server, binding to localhost on port 9999
#with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
with socketserver.TCPServer(('', PORT), MyTCPHandler) as server:
# Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
server.serve_forever()
This socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server example is
modify from
Python 3 socketserver.TCPServer Example. I assume socketserver.TCPServer will handle Ctrl-C with port close. But
in my test, SOMETIMES throw OSError of "Address already in use". In my practice,
try pressing Ctrl-C in REPL/restart repeatedly.
In my usage scenario: The Raspberry Pi 4B/8G is installed with HQ Camera
Module (mount with manual focus lens) and a 4 inch HDMI IPS Touch Display.
Remote control with Android with xrdp/Microsoft Remote Desktop. Such that I
can control camera on remote Android device, adjust focus/aperture on the
lens, and check the effect on local HDMI preview at real-time.
Python3 code, qCam240_20210323.py
import sys
import picamera
from pkg_resources import require
import time
import picamera
from PyQt5.QtWidgets import (QApplication, QWidget,
QPushButton, QLabel, QRadioButton,
QMessageBox, QHBoxLayout, QVBoxLayout)
from PyQt5.QtGui import QPixmap, QImage
from PyQt5.Qt import qRed, qGreen, qBlue
from signal import signal, SIGINT
print(sys.version)
print(require('picamera'))
rpi_icon = 'rpi_icon_240.png'
class AppWindow(QWidget):
camPreviewState = False #not in Preview
def __init__(self):
super().__init__()
self.camera = picamera.PiCamera()
self.camera.resolution = (240, 240)
lbSysInfo = QLabel('Python:\n' + sys.version)
lbPicameraInfo = QLabel(str(require('picamera')))
vboxInfo = QVBoxLayout()
vboxInfo.addWidget(lbSysInfo)
vboxInfo.addWidget(lbPicameraInfo)
#setup UI
btnPreview = QPushButton("Start Preview", self)
btnPreview.clicked.connect(self.evBtnPreviewClicked)
btnCapture = QPushButton("Capture", self)
btnCapture.clicked.connect(self.evBtnCaptureClicked)
lbFileName = QLabel('save as (Desktop/):')
self.rbtnImage = QRadioButton('image.jpg')
self.rbtnImage.setChecked(True)
self.rbtnStamp = QRadioButton('img_<timestamp>.jpg')
vboxCamControl = QVBoxLayout()
vboxCamControl.addWidget(btnPreview)
vboxCamControl.addWidget(btnCapture)
vboxCamControl.addWidget(lbFileName)
vboxCamControl.addWidget(self.rbtnImage)
vboxCamControl.addWidget(self.rbtnStamp)
vboxCamControl.addStretch()
self.lbImg = QLabel(self)
self.lbImg.resize(240, 240)
self.lbImg.setStyleSheet("border: 1px solid black;")
try:
with open(rpi_icon):
pixmap = QPixmap(rpi_icon)
self.lbImg.setPixmap(pixmap)
except FileNotFoundError:
print('File Not Found Error')
hboxCam = QHBoxLayout()
hboxCam.addWidget(self.lbImg)
hboxCam.addLayout(vboxCamControl)
self.lbPath = QLabel(self)
vboxMain = QVBoxLayout()
vboxMain.addLayout(vboxInfo)
vboxMain.addLayout(hboxCam)
vboxMain.addWidget(self.lbPath)
vboxMain.addStretch()
self.setLayout(vboxMain)
self.setGeometry(100, 100, 500,400)
self.show()
def evBtnPreviewClicked(self):
if self.camPreviewState:
print('Stop Preview')
self.camera.stop_preview()
self.sender().setText('Start Preview')
self.camPreviewState = False
else:
print('Start Preview')
self.camera.start_preview()
self.sender().setText('Stop Preview')
self.camPreviewState = True
def evBtnCaptureClicked(self):
print('evBtnCaptureClicked()')
print("Capture")
if self.rbtnImage.isChecked():
targetPath="/home/pi/Desktop/image.jpg"
else:
timeStamp = time.strftime("%Y%m%d-%H%M%S")
targetPath="/home/pi/Desktop/img_"+timeStamp+".jpg"
print(targetPath)
self.camera.capture(targetPath)
self.lbPath.setText(targetPath)
try:
with open(targetPath):
pixmap = QPixmap(targetPath)
self.lbImg.setPixmap(pixmap)
#as a exercise, get some info from pixmap
print('\npixmap:')
print(pixmap)
print(type(pixmap))
print(str(pixmap.width()) + " : " + str(pixmap.height()))
print()
print('convert to Image')
qim = pixmap.toImage()
print(qim)
print(type(qim))
print()
print('read a pixel from image')
qrgb = qim.pixel(0, 0)
print(hex(qrgb))
print(type(qrgb))
r, g, b = qRed(qrgb), qGreen(qrgb), qBlue(qrgb)
print([hex(r), hex(g), hex(b)])
print()
except FileNotFoundError:
print('File Not Found Error')
def closeEvent(self, event):
confirmClose = QMessageBox.question(self,
"Quit App?",
"Confirm to Quit?",
QMessageBox.No | QMessageBox.Yes,
QMessageBox.Yes)
if confirmClose == QMessageBox.Yes:
print('Confirmed Close')
self.camera.close()
event.accept()
else:
event.ignore()
if __name__ == '__main__':
print('run __main__')
app = QApplication(sys.argv)
window = AppWindow()
sys.exit(app.exec_())
print("- bye -")
Download the thumbnail image, save as "rpi_icon_240.png" in the same
folder. Used as a default image only.
The above exercise run on version MicroPython version 'v1.14 on 2021-03-17',
SPI2 defined with default pin assignment.
Recently, I tested it on 'MicroPython v1.14 2021-02-02' (stable version
esp32spiram-idf4-20210202-v1.14.bin). It's founded there are NO default pin
assigned to SPI.
So you have to define the pins in your code,like this:
On current latest unstable version esp32spiram-20210407-unstable-v1.14-142-gcb396827f.bin, default pins are defined. Pins can be omitted using default assignment.
This exercise program Raspberry Pi Pico/MicroPython + ESP32-S (ESP-AT) as WiFi
TCP client to remote control ESP32-DevKitC V4/MicroPython WiFi TCP server
onboard LED.
In Client side:
ESP32-S
is a wireless module based on ESP32. It's flashed with AT-command firmware
ESP-AT. It's act as a WiFi co-processor. Raspberry Pi Pico/MicroPython send
AT-command to ESP32-S via UART. Please note that for ESP32 flashed with
ESP-AT: UART1 (IO16/IO17) is used to send AT commands and receive AT
responses, connected to GP0/GP1 of Pico.
Pico GP15 connected to ESP32-S EN pin, to reset it in power up.
Pico GP16 is used control remote LED.
In Server side:
ESP32-DevKitC V4 (with ESP32-WROVER-E module)/MicroPython is programed as WiFi
server, receive command from client to turn ON/OFF LED accordingly.
Connection:
MicroPython code:
Client side, mpyPico_ESP32S_remoteCli_.py run on Raspberry Pi Pico.
import uos
import machine
import utime
"""
Raspberry Pi Pico/MicroPython + ESP32-S exercise
ESP32-S with AT-command firmware (ESP-AT):
---------------------------------------------------
AT version:2.1.0.0(883f7f2 - Jul 24 2020 11:50:07)
SDK version:v4.0.1-193-ge7ac221
compile time(0ad6331):Jul 28 2020 02:47:21
Bin version:2.1.0WROM-3)
---------------------------------------------------
Pico send AT command to ESP32-S via UART,
Send command to server (ESP32/MicroPython)
to turn ON/OFF LED on server.
---------------------------------------------------
Connection:
powered by separated power supply
Pico ESP32-S
GND GND
GP0 (TX) (pin 1) IO16 (RXD)
GP1 (RX) (pin 2) IO17 (TXD)
GP15 (pin 20) EN
GP16 (pin 21) button
---------------------------------------------------
"""
#server port & ip hard-coded,
#have to match with server side setting
server_ip="192.168.4.1"
server_port=8000
network_ssid = "ESP32-ssid"
network_password = "password"
ESP_EN = 15
PIN_ESP_EN = machine.Pin(ESP_EN, machine.Pin.IN, machine.Pin.PULL_UP)
DIn = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_UP)
print()
print("Machine: \t" + uos.uname()[4])
print("MicroPython: \t" + uos.uname()[3])
#indicate program started visually
led_onboard = machine.Pin(25, machine.Pin.OUT)
led_onboard.value(0) # Toggle onboard LED
utime.sleep(0.5) # to indiacte program start
led_onboard.value(1)
utime.sleep(1)
led_onboard.value(0)
#Reset ESP
PIN_ESP_EN = machine.Pin(ESP_EN, machine.Pin.OUT)
PIN_ESP_EN.value(1)
utime.sleep(0.5)
PIN_ESP_EN.value(0)
utime.sleep(0.5)
PIN_ESP_EN.value(1)
PIN_ESP_EN = machine.Pin(ESP_EN, machine.Pin.IN, machine.Pin.PULL_UP)
uart = machine.UART(0, baudrate=115200)
print(uart)
RES_OK = b'OK\r\n'
len_OK = len(RES_OK)
RESULT_OK = '0'
RESULT_TIMEOUT = '1'
def sendCMD_waitResult(cmd, timeout=2000):
print("CMD: " + cmd)
uart.write(cmd)
prvMills = utime.ticks_ms()
result = RESULT_TIMEOUT
resp = b""
while (utime.ticks_ms()-prvMills)<timeout:
if uart.any():
resp = b"".join([resp, uart.read(1)])
resp_len = len(resp)
if resp[resp_len-len_OK:]==RES_OK:
print(RES_OK + " found!")
result = RESULT_OK
break
print("resp:")
try:
print(resp.decode())
except UnicodeError:
print(resp)
return result
#to make it simple to detect, RMCMD & RMSTA designed same length
#Remote Command from client to serve
RMCMD_len = 6
RMCMD_ON = "LEDONN" #turn LED ON
RMCMD_OFF = "LEDOFF" #turn LED OFF
#Remote status from server to client
RMSTA_len = 6
RMSTA_timeout = "timeout" #time out without/unknown reply
RMSTA_LEDON = "LedOnn"
RMSTA_LEDOFF = "LedOff"
"""
#Expected flow to send command to wifi is:
Pico (client) to ESP-01S response from ESP-01S to Pico
AT+CIPSEND=<cmd len>\r\n
AT+CIPSEND=<cmd len>\r\n
OK\r\n
>\r\n
<cmd>
Recv x bytes\r\n
SEND OK\r\n ---> ESP (server)
<--- ESP (server) end with OK\r\n
+IPD,10:<RMSTA>OK\r\n
+IPD,2:\r\n
"""
def sendRemoteCmd(rmcmd, timeout=2000):
result = RMSTA_timeout
if sendCMD_waitResult('AT+CIPSEND=' + str(len(rmcmd)) + '\r\n', timeout)==RESULT_OK:
#dummy read '>'
while not uart.any():
pass
print(uart.read(1))
print("Remote CMD: " + rmcmd)
if sendCMD_waitResult(rmcmd) == RESULT_OK:
endMills = utime.ticks_ms() + timeout
resp = b""
while utime.ticks_ms()<endMills:
if uart.any():
resp = b"".join([resp, uart.read(1)])
resp_len = len(resp)
if resp[resp_len-len_OK:]==RES_OK:
print(RES_OK + " found!")
rmSta=resp[resp_len-len_OK-RMSTA_len:resp_len-len_OK]
strRmSta=rmSta.decode() #convert bytes to string
print(strRmSta)
if strRmSta == RMSTA_LEDON:
result = strRmSta
elif strRmSta == RMSTA_LEDOFF:
result = strRmSta
break
print("resp:")
try:
print(resp.decode())
except UnicodeError:
print(resp)
return result
def sendCMD_waitResp(cmd, timeout=2000):
print("CMD: " + cmd)
uart.write(cmd)
waitResp(timeout)
print()
def waitResp(timeout=2000):
prvMills = utime.ticks_ms()
resp = b""
while (utime.ticks_ms()-prvMills)<timeout:
if uart.any():
resp = b"".join([resp, uart.read(1)])
print("resp:")
try:
print(resp.decode())
except UnicodeError:
print(resp)
"""
everytimes send command to server:
- join ESP32 network
- connect to ESP32 socket
- send command to server and receive status
"""
def connectRemoteSendCmd(cmdsend):
clearRxBuf()
print("join wifi network: " + "ESP32-ssid")
while sendCMD_waitResult('AT+CWJAP="' + network_ssid + '","'
+ network_password + '"\r\n') != RESULT_OK:
pass
sendCMD_waitResp('AT+CIFSR\r\n') #Obtain the Local IP Address
sendCMD_waitResult('AT+CIPSTATUS\r\n')
print("wifi network joint")
print("connect socket")
if sendCMD_waitResult('AT+CIPSTART="TCP","'
+ server_ip
+ '",'
+ str(server_port) + '\r\n', timeout=5000) == RESULT_OK:
sendCMD_waitResult('AT+CIPSTATUS\r\n')
print("RMST: " + sendRemoteCmd(rmcmd=cmdsend))
clearRxBuf()
sendCMD_waitResult('AT+CIPSTATUS\r\n')
sendCMD_waitResult('AT+CWQAP\r\n')
def clearRxBuf():
print("--- clear Rx buffer ---")
buf = b""
while uart.any():
buf = b"".join([buf, uart.read(1)])
print(buf)
print("-----------------------")
led_onboard.value(0)
clearRxBuf()
sendCMD_waitResult('AT\r\n') #Test AT startup
sendCMD_waitResult('AT+CWMODE=1\r\n') #Set the Wi-Fi mode 1 = Station mode
sendCMD_waitResult('AT+CIPMUX=0\r\n') #single connection.
led_onboard.value(1)
connectRemoteSendCmd(cmdsend=RMCMD_ON)
utime.sleep(1)
connectRemoteSendCmd(cmdsend=RMCMD_OFF)
#fast toggle led 5 times to indicate startup finished
for i in range(5):
led_onboard.value(0)
utime.sleep(0.2)
led_onboard.value(1)
utime.sleep(0.2)
led_onboard.value(0)
print("Started")
print("waiting for button")
#read digital input every 10ms
dinMills = utime.ticks_ms() + 30
prvDin = 1
debounced = False
while True:
if utime.ticks_ms() > dinMills:
dinMills = utime.ticks_ms() + 30
curDin = DIn.value()
if curDin != prvDin:
#Din changed
prvDin = curDin
debounced = False
else:
if not debounced:
#DIn changed for > 30ms
debounced = True
if curDin:
connectRemoteSendCmd(cmdsend=RMCMD_OFF)
else:
connectRemoteSendCmd(cmdsend=RMCMD_ON)
Server side, upyESP32_AP_RemoteSvr_.py run on ESP32-DevKitC V4.
import utime
import uos
import network
import usocket
from machine import Pin
"""
ESP32/MicroPython exercise:
ESP32 act as Access Point,
and setup a simple TCP server
receive command from client and turn ON/OFF LED,
and send back status.
"""
ssid= "ESP32-ssid"
password="password"
led=Pin(13,Pin.OUT)
print("----- MicroPython -----")
for u in uos.uname():
print(u)
print("-----------------------")
for i in range(3):
led.on()
utime.sleep(0.5)
led.off()
utime.sleep(0.5)
ap = network.WLAN(network.AP_IF) # Access Point
ap.config(essid=ssid,
password=password,
authmode=network.AUTH_WPA_WPA2_PSK)
ap.config(max_clients=1) # max number of client
ap.active(True) # activate the access point
print(ap.ifconfig())
print(dir(ap))
mysocket = usocket.socket(usocket.AF_INET, usocket.SOCK_STREAM)
mysocket.setsockopt(usocket.SOL_SOCKET, usocket.SO_REUSEADDR, 1)
port = 8000
mysocket.bind(('',8000))
print("bind: " + str(port))
mysocket.listen(1)
#tomake it simple to detect, RMCMD & RMSTA designed same length
#Remote Command from client to serve
RMCMD_len = 6
RMCMD_ON = "LEDONN" #turn LED ON
RMCMD_OFF = "LEDOFF" #turn LED OFF
#Remote status from server to client
RMSTA_len = 6
RMSTA_timeout = "timeout" #time out without/unknown reply
RMSTA_LEDON = "LedOnn"
RMSTA_LEDOFF = "LedOff"
while True:
conn, addr = mysocket.accept()
print('Connected from: %s' % str(addr))
print()
request = conn.recv(1024)
print('request: %s' % str(request))
print()
strRqs = request.decode()
print("strRqs: "+strRqs)
if strRqs==RMCMD_ON:
conn.send(RMSTA_LEDON+'OK\r\n')
led.on()
elif strRqs==RMCMD_OFF:
conn.send(RMSTA_LEDOFF+'OK\r\n')
led.off()
else:
#unknown command
conn.send(request.upper())
conn.send('\r\n')
conn.close()
It's a Python3 code run on Raspberry Pi to control Camera Module with various
setting. The preview display on local HDMI.
In my usage scenario: The Raspberry Pi 4B/8G is installed with HQ Camera
Module (mount with manual focus lens) and a
4 inch HDMI IPS Touch Display. Remote control with Android with
xrdp/Microsoft Remote Desktop. Such that I can control and change setting on remote Android device,
adjust focus/aperture on the lens, and check the effect on local HDMI
preview at real-time.
It's a long time ago, I make a similar code with preview stream video,
both control and preview on remote desktop, Python to capture image from Pi Camera Module, with image effects. But I'm not satisfied by the delay of stream video, that's why I
re-develop this code again.
The lens shown on the video is a Nikkor ais 28mm f2.8 manual focus lens, connected to HQ Camera Module via a Nikon F to C mount adapter.
As this is writing, picamera is still 1.13, so the maximum resolution is 3280x2464 for V2, not HQ.
~ Another minimum version: with minimum functions preview and capture only, using PyQt5 GUI, fixed resolution 240x240, and display the captured image on GUI. You can also choice save file name; image.jpg or img_<timestamp>.jpg, under Desktop folder.
"""
Raspperry Pi Pico exercise display on ili9341 SPI Display
using rdagger/micropython-ili9341,
MicroPython ILI9341 Display and XPT2046 Touch Screen Drivers
https://github.com/rdagger/micropython-ili9341
"""
from machine import Pin, SPI
from sys import implementation
from os import uname
import utime
import ili9341
from xglcd_font import XglcdFont
import mySetup
print(implementation.name)
print(uname()[3])
print(uname()[4])
print(SPI(0))
print(SPI(1))
display = mySetup.createMyDisplay()
print('Loading fonts...')
print('Loading unispace')
unispace = XglcdFont('fonts/Unispace12x24.c', 12, 24)
display.draw_text(0, 0, ili9341.__name__, unispace,
ili9341.color565(255, 128, 0))
display.draw_text(0, 25, ili9341.implementation.name, unispace,
ili9341.color565(0, 0, 200))
display.draw_text(0, 50, str(ili9341.implementation.version), unispace,
ili9341.color565(0, 0, 200))
display.draw_text(0, 100, "https://github.com/", unispace,
ili9341.color565(200, 200, 200))
display.draw_text(0, 125, "rdagger/micropython-ili9341", unispace,
ili9341.color565(200, 200, 200))
display.draw_text(0, 175, "ABCDEFGHIJKLMNOPQRS", unispace,
ili9341.color565(200, 200, 200))
display.draw_text(0, 200, "TUVWXYZ", unispace,
ili9341.color565(200, 200, 200))
display.draw_text(0, 225, "abcdefghijklmnopqrs", unispace,
ili9341.color565(200, 200, 200))
display.draw_text(0, 250, "tuvwxyz", unispace,
ili9341.color565(200, 200, 200))
display.draw_text(0, 275, "01234567890", unispace,
ili9341.color565(200, 200, 200))
display.draw_text(0, 300, "~!@#$%^&*()_+`-={}[]", unispace,
ili9341.color565(200, 200, 200))
display.draw_text(0, 325, "\|;:'<>,.?/", unispace,
ili9341.color565(200, 200, 200))
for i in range(320):
display.scroll(i)
utime.sleep(0.02)
for i in range(320, 0, -1):
display.scroll(i)
utime.sleep(0.02)
utime.sleep(0.5)
# Display inversion on
display.write_cmd(display.INVON)
utime.sleep(2)
# Display inversion off
display.write_cmd(display.INVOFF)
while True:
pass
print("- bye -")
I also modify some of the examples in the library.
demo_bouncing_boxes_.py
"""ILI9341 demo (bouncing boxes)."""
from machine import Pin, SPI
from random import random, seed
from ili9341 import Display, color565
from utime import sleep_us, ticks_cpu, ticks_us, ticks_diff
import mySetup
class Box(object):
"""Bouncing box."""
def __init__(self, screen_width, screen_height, size, display, color):
"""Initialize box.
Args:
screen_width (int): Width of screen.
screen_height (int): Width of height.
size (int): Square side length.
display (ILI9341): display object.
color (int): RGB565 color value.
"""
self.size = size
self.w = screen_width
self.h = screen_height
self.display = display
self.color = color
# Generate non-zero random speeds between -5.0 and 5.0
seed(ticks_cpu())
r = random() * 10.0
self.x_speed = 5.0 - r if r < 5.0 else r - 10.0
r = random() * 10.0
self.y_speed = 5.0 - r if r < 5.0 else r - 10.0
self.x = self.w / 2.0
self.y = self.h / 2.0
self.prev_x = self.x
self.prev_y = self.y
def update_pos(self):
"""Update box position and speed."""
x = self.x
y = self.y
size = self.size
w = self.w
h = self.h
x_speed = abs(self.x_speed)
y_speed = abs(self.y_speed)
self.prev_x = x
self.prev_y = y
if x + size >= w - x_speed:
self.x_speed = -x_speed
elif x - size <= x_speed + 1:
self.x_speed = x_speed
if y + size >= h - y_speed:
self.y_speed = -y_speed
elif y - size <= y_speed + 1:
self.y_speed = y_speed
self.x = x + self.x_speed
self.y = y + self.y_speed
def draw(self):
"""Draw box."""
x = int(self.x)
y = int(self.y)
size = self.size
prev_x = int(self.prev_x)
prev_y = int(self.prev_y)
self.display.fill_hrect(prev_x - size,
prev_y - size,
size, size, 0)
self.display.fill_hrect(x - size,
y - size,
size, size, self.color)
def test():
"""Bouncing box."""
try:
# Baud rate of 40000000 seems about the max
#spi = SPI(1, baudrate=40000000, sck=Pin(14), mosi=Pin(13))
#display = Display(spi, dc=Pin(4), cs=Pin(16), rst=Pin(17))
display = mySetup.createMyDisplay()
display.clear()
colors = [color565(255, 0, 0),
color565(0, 255, 0),
color565(0, 0, 255),
color565(255, 255, 0),
color565(0, 255, 255),
color565(255, 0, 255)]
sizes = [12, 11, 10, 9, 8, 7]
boxes = [Box(239, 319, sizes[i], display,
colors[i]) for i in range(6)]
while True:
timer = ticks_us()
for b in boxes:
b.update_pos()
b.draw()
# Attempt to set framerate to 30 FPS
timer_dif = 33333 - ticks_diff(ticks_us(), timer)
if timer_dif > 0:
sleep_us(timer_dif)
except KeyboardInterrupt:
display.cleanup()
test()
demo_colored_squares_.py
"""ILI9341 demo (colored squares)."""
from time import sleep
from ili9341 import Display
from machine import Pin, SPI
from sys import modules
import mySetup
RED = const(0XF800) # (255, 0, 0)
GREEN = const(0X07E0) # (0, 255, 0)
BLUE = const(0X001F) # (0, 0, 255)
YELLOW = const(0XFFE0) # (255, 255, 0)
FUCHSIA = const(0XF81F) # (255, 0, 255)
AQUA = const(0X07FF) # (0, 255, 255)
MAROON = const(0X8000) # (128, 0, 0)
DARKGREEN = const(0X0400) # (0, 128, 0)
NAVY = const(0X0010) # (0, 0, 128)
TEAL = const(0X0410) # (0, 128, 128)
PURPLE = const(0X8010) # (128, 0, 128)
OLIVE = const(0X8400) # (128, 128, 0)
ORANGE = const(0XFC00) # (255, 128, 0)
DEEP_PINK = const(0XF810) # (255, 0, 128)
CHARTREUSE = const(0X87E0) # (128, 255, 0)
SPRING_GREEN = const(0X07F0) # (0, 255, 128)
INDIGO = const(0X801F) # (128, 0, 255)
DODGER_BLUE = const(0X041F) # (0, 128, 255)
CYAN = const(0X87FF) # (128, 255, 255)
PINK = const(0XFC1F) # (255, 128, 255)
LIGHT_YELLOW = const(0XFFF0) # (255, 255, 128)
LIGHT_CORAL = const(0XFC10) # (255, 128, 128)
LIGHT_GREEN = const(0X87F0) # (128, 255, 128)
LIGHT_SLATE_BLUE = const(0X841F) # (128, 128, 255)
WHITE = const(0XFFF) # (255, 255, 255)
colors = [RED,
GREEN,
BLUE,
YELLOW,
FUCHSIA,
AQUA,
MAROON,
DARKGREEN,
NAVY,
TEAL,
PURPLE,
OLIVE,
ORANGE,
DEEP_PINK,
CHARTREUSE,
SPRING_GREEN,
INDIGO,
DODGER_BLUE,
CYAN,
PINK,
LIGHT_YELLOW,
LIGHT_CORAL,
LIGHT_GREEN,
LIGHT_SLATE_BLUE,
WHITE ]
def test():
"""Test code."""
"""
# Baud rate of 40000000 seems about the max
spi = SPI(0, baudrate=40000000, sck=Pin(TFT_CLK_PIN), mosi=Pin(TFT_MOSI_PIN))
display = Display(spi, dc=Pin(TFT_DC_PIN), cs=Pin(TFT_CS_PIN), rst=Pin(TFT_RST_PIN))
"""display = mySetup.createMyDisplay()"""
# Build color list from all upper case constants (lazy approach)
colors = [getattr(modules[__name__], name) for name in dir(
modules[__name__]) if name.isupper() and name is not 'SPI']
"""
colors.sort()
c = 0
for x in range(0, 240, 48):
for y in range(0, 320, 64):
display.fill_rectangle(x, y, 47, 63, colors[c])
c += 1
sleep(9)
display.cleanup()
test()
demo_color_palette_.py
"""ILI9341 demo (color palette)."""
from time import sleep
from ili9341 import Display, color565
from machine import Pin, SPI
import mySetup
def hsv_to_rgb(h, s, v):
"""
Convert HSV to RGB (based on colorsys.py).
Args:
h (float): Hue 0 to 1.
s (float): Saturation 0 to 1.
v (float): Value 0 to 1 (Brightness).
"""
if s == 0.0:
return v, v, v
i = int(h * 6.0)
f = (h * 6.0) - i
p = v * (1.0 - s)
q = v * (1.0 - s * f)
t = v * (1.0 - s * (1.0 - f))
i = i % 6
v = int(v * 255)
t = int(t * 255)
p = int(p * 255)
q = int(q * 255)
if i == 0:
return v, t, p
if i == 1:
return q, v, p
if i == 2:
return p, v, t
if i == 3:
return p, q, v
if i == 4:
return t, p, v
if i == 5:
return v, p, q
def test():
"""Test code."""
# Baud rate of 40000000 seems about the max
#spi = SPI(1, baudrate=40000000, sck=Pin(14), mosi=Pin(13))
#display = Display(spi, dc=Pin(4), cs=Pin(16), rst=Pin(17))
display = mySetup.createMyDisplay()
c = 0
for x in range(0, 240, 20):
for y in range(0, 320, 20):
color = color565(*hsv_to_rgb(c / 192, 1, 1))
display.fill_circle(x + 9, y + 9, 9, color)
c += 1
sleep(9)
display.cleanup()
test()
demo_color_wheel_.py
"""ILI9341 demo (color wheel)."""
from time import sleep
from ili9341 import Display, color565
from machine import Pin, SPI
from math import cos, pi, sin
import mySetup
HALF_WIDTH = const(120)
HALF_HEIGHT = const(160)
CENTER_X = const(119)
CENTER_Y = const(159)
ANGLE_STEP_SIZE = 0.05 # Decrease step size for higher resolution
PI2 = pi * 2
def hsv_to_rgb(h, s, v):
"""
Convert HSV to RGB (based on colorsys.py).
Args:
h (float): Hue 0 to 1.
s (float): Saturation 0 to 1.
v (float): Value 0 to 1 (Brightness).
"""
if s == 0.0:
return v, v, v
i = int(h * 6.0)
f = (h * 6.0) - i
p = v * (1.0 - s)
q = v * (1.0 - s * f)
t = v * (1.0 - s * (1.0 - f))
i = i % 6
v = int(v * 255)
t = int(t * 255)
p = int(p * 255)
q = int(q * 255)
if i == 0:
return v, t, p
if i == 1:
return q, v, p
if i == 2:
return p, v, t
if i == 3:
return p, q, v
if i == 4:
return t, p, v
if i == 5:
return v, p, q
def test():
"""Test code."""
# Baud rate of 40000000 seems about the max
#spi = SPI(1, baudrate=40000000, sck=Pin(14), mosi=Pin(13))
#display = Display(spi, dc=Pin(4), cs=Pin(16), rst=Pin(17))
display = mySetup.createMyDisplay()
x, y = 0, 0
angle = 0.0
# Loop all angles from 0 to 2 * PI radians
while angle < PI2:
# Calculate x, y from a vector with known length and angle
x = int(CENTER_X * sin(angle) + HALF_WIDTH)
y = int(CENTER_Y * cos(angle) + HALF_HEIGHT)
color = color565(*hsv_to_rgb(angle / PI2, 1, 1))
display.draw_line(x, y, CENTER_X, CENTER_Y, color)
angle += ANGLE_STEP_SIZE
sleep(5)
for r in range(CENTER_X, 0, -1):
color = color565(*hsv_to_rgb(r / HALF_WIDTH, 1, 1))
display.fill_circle(CENTER_X, CENTER_Y, r, color)
sleep(9)
display.cleanup()
test()
Run xpt_cal_.py, touch the corners to found the min/max of x/y. The detected
min/max of x/y will be shown on screen. (Please check the
video, y_max=2047 may be mis-detected, but very close. It apear before
touched.)