This commit is contained in:
44
config.py
44
config.py
@@ -1,5 +1,49 @@
|
|||||||
from micropython import const
|
from micropython import const
|
||||||
|
|
||||||
|
|
||||||
|
from machine import Pin, SPI
|
||||||
|
from time import sleep_ms
|
||||||
|
|
||||||
|
# ----------------------------epaper配置-------------------------------------------------
|
||||||
|
|
||||||
|
# SPI引脚配置
|
||||||
|
sck = Pin(47) # SCK pin47
|
||||||
|
miso = Pin(46) # MISO pin46
|
||||||
|
mosi = Pin(21) # SDI/MOSI pin21
|
||||||
|
|
||||||
|
# 控制引脚配置
|
||||||
|
dc = Pin(40) # D/C pin40
|
||||||
|
cs = Pin(45) # CS pin45
|
||||||
|
rst = Pin(41) # RES pin41
|
||||||
|
busy = Pin(42) # BUSY pin42
|
||||||
|
|
||||||
|
# 按钮引脚配置
|
||||||
|
btn1 = Pin(46, Pin.IN, Pin.PULL_UP) # 按钮1连接到引脚46
|
||||||
|
btn2 = Pin(20, Pin.IN, Pin.PULL_UP) # 按钮2连接到引脚20
|
||||||
|
btn3 = Pin(12, Pin.IN, Pin.PULL_UP) # 按钮3连接到引脚12
|
||||||
|
btn4 = Pin(11, Pin.IN, Pin.PULL_UP) # 按钮4连接到引脚11
|
||||||
|
|
||||||
|
# 蜂鸣器引脚配置
|
||||||
|
buzzer_pin = 14 # 蜂鸣器连接到引脚14
|
||||||
|
|
||||||
|
# epaper屏幕尺寸
|
||||||
|
WIDTH = 400
|
||||||
|
HEIGHT = 300
|
||||||
|
|
||||||
|
# 初始化 SPI2(HSPI/VSPI 视固件而定)
|
||||||
|
spi = SPI(2, baudrate=2_000_000, polarity=0, phase=0,
|
||||||
|
sck=sck, miso=miso, mosi=mosi)
|
||||||
|
|
||||||
|
# 如果你板子上真有单独的 EPD 电源控制 FET,就按实际 IO 改;
|
||||||
|
# 若只是直接 3.3V 供电,可以把下面这一段去掉。
|
||||||
|
epd_power = Pin(2, Pin.OUT)
|
||||||
|
epd_power.on()
|
||||||
|
sleep_ms(10)
|
||||||
|
|
||||||
|
# ----------------------------epaper配置-------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class BoardConfig:
|
class BoardConfig:
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|||||||
312
epaper_diver/epaper4in2.py
Normal file
312
epaper_diver/epaper4in2.py
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
"""
|
||||||
|
MicroPython Good Display GDEQ042T81 (GDEY042T81)
|
||||||
|
|
||||||
|
Based on MicroPython Waveshare 4.2" Black/White GDEW042T2 e-paper display driver
|
||||||
|
https://github.com/mcauser/micropython-waveshare-epaper
|
||||||
|
|
||||||
|
licensed under the MIT License
|
||||||
|
Copyright (c) 2017 Waveshare
|
||||||
|
Copyright (c) 2018 Mike Causer
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
MicroPython Good Display GDEQ042T81 (GDEY042T81) e-paper display driver
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
Copyright (c) 2024 Martin Maly
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from micropython import const
|
||||||
|
from time import sleep_ms
|
||||||
|
try:
|
||||||
|
from buzzer import system_buzzer
|
||||||
|
except ImportError:
|
||||||
|
system_buzzer = None
|
||||||
|
|
||||||
|
# Display resolution
|
||||||
|
EPD_WIDTH = const(400)
|
||||||
|
EPD_HEIGHT = const(300)
|
||||||
|
BUSY = const(0) # 0=busy, 1=idle
|
||||||
|
|
||||||
|
class EPD:
|
||||||
|
def __init__(self, spi, cs, dc, rst, busy):
|
||||||
|
self.spi = spi
|
||||||
|
self.cs = cs
|
||||||
|
self.dc = dc
|
||||||
|
self.rst = rst
|
||||||
|
self.busy = busy
|
||||||
|
self.cs.init(self.cs.OUT, value=1)
|
||||||
|
self.dc.init(self.dc.OUT, value=0)
|
||||||
|
self.rst.init(self.rst.OUT, value=0)
|
||||||
|
self.busy.init(self.busy.IN)
|
||||||
|
self.width = EPD_WIDTH
|
||||||
|
self.height = EPD_HEIGHT
|
||||||
|
self.powered = False
|
||||||
|
self.init_done = False
|
||||||
|
self.hibernate = True
|
||||||
|
self.use_fast_update = True
|
||||||
|
# 添加刷新计数器,用于控制全屏刷新频率
|
||||||
|
self.refresh_count = 0
|
||||||
|
# 每N次局部刷新后执行一次全屏刷新,防止残影积累
|
||||||
|
self.partial_refresh_limit = 5
|
||||||
|
# 强制全屏刷新标志
|
||||||
|
self.force_full_refresh = False
|
||||||
|
|
||||||
|
def _command(self, command, data=None):
|
||||||
|
self.dc(0)
|
||||||
|
self.cs(0)
|
||||||
|
self.spi.write(bytearray([command]))
|
||||||
|
self.cs(1)
|
||||||
|
if data is not None:
|
||||||
|
self._data(data)
|
||||||
|
|
||||||
|
def _data(self, data):
|
||||||
|
self.dc(1)
|
||||||
|
self.cs(0)
|
||||||
|
self.spi.write(data)
|
||||||
|
self.cs(1)
|
||||||
|
|
||||||
|
def _ndata(self, data):
|
||||||
|
self._data(bytearray([data]))
|
||||||
|
|
||||||
|
def pwr_on(self):
|
||||||
|
if self.powered == False:
|
||||||
|
self._command(0x22, b'\xe0')
|
||||||
|
self._command(0x20)
|
||||||
|
self.wait_until_idle()
|
||||||
|
self.powered = True
|
||||||
|
|
||||||
|
def pwr_off(self):
|
||||||
|
if self.powered == True:
|
||||||
|
self._command(0x22, b'\x83')
|
||||||
|
self._command(0x20)
|
||||||
|
self.wait_until_idle()
|
||||||
|
self.powered = False
|
||||||
|
|
||||||
|
#set partial
|
||||||
|
def set_partial(self, x, y, w, h):
|
||||||
|
self._command(0x11,b'\x03')
|
||||||
|
self._command(0x44)
|
||||||
|
self._ndata(x // 8)
|
||||||
|
self._ndata((x + w - 1) // 8)
|
||||||
|
self._command(0x45)
|
||||||
|
self._ndata(y % 256)
|
||||||
|
self._ndata(y // 256)
|
||||||
|
self._ndata((y+h-1) % 256)
|
||||||
|
self._ndata((y+h-1) // 256)
|
||||||
|
self._command(0x4E)
|
||||||
|
self._ndata(x // 8)
|
||||||
|
self._command(0x4F)
|
||||||
|
self._ndata(y % 256)
|
||||||
|
self._ndata(y // 256)
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
if self.hibernate==True:
|
||||||
|
self.reset()
|
||||||
|
sleep_ms(100)
|
||||||
|
#self.wait_until_idle()
|
||||||
|
self._command(const(0x12)) #SWRESET
|
||||||
|
self.wait_until_idle()
|
||||||
|
|
||||||
|
# 优化驱动初始化参数,确保与GDEY042T81规格匹配
|
||||||
|
self._command(0x01,b'\x2B\x01\x00') #MUX 设置
|
||||||
|
self._command(0x21,b'\x40\x00') # 显示更新控制
|
||||||
|
self._command(0x3C,b'\x05') # 边界波形控制,减少残影
|
||||||
|
self._command(0x18,b'\x80') # 读取内部温度传感器
|
||||||
|
self._command(0x0C,b'\x8B\x00\x00') # 设置开始和结束阶段,优化刷新
|
||||||
|
|
||||||
|
self.set_partial(0, 0, self.width, self.height)
|
||||||
|
self.init_done = True
|
||||||
|
|
||||||
|
def wait_until_idle(self):
|
||||||
|
while self.busy.value() == BUSY:
|
||||||
|
sleep_ms(100)
|
||||||
|
print("等待墨水屏空闲")
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.rst(0)
|
||||||
|
sleep_ms(200)
|
||||||
|
self.rst(1)
|
||||||
|
sleep_ms(200)
|
||||||
|
|
||||||
|
def update_full(self):
|
||||||
|
#update Full
|
||||||
|
print("执行全屏更新")
|
||||||
|
self._command(0x21,b'\x40\x00')
|
||||||
|
if self.use_fast_update == False:
|
||||||
|
self._command(0x22,b'\xf7')
|
||||||
|
else:
|
||||||
|
self._command(0x1A, b'\x64') # 快速刷新设置
|
||||||
|
self._command(0x22,b'\xd7')
|
||||||
|
self._command(0x20)
|
||||||
|
self.wait_until_idle()
|
||||||
|
print("更新完成", self.busy.value())
|
||||||
|
|
||||||
|
# 添加专门的全屏刷新方法,用于清除残影
|
||||||
|
def clear_screen(self, double_refresh=True):
|
||||||
|
"""执行全屏刷新以清除残影
|
||||||
|
|
||||||
|
参数:
|
||||||
|
double_refresh: 是否执行两次刷新以彻底清除残影,默认为True
|
||||||
|
"""
|
||||||
|
if double_refresh:
|
||||||
|
print("执行双次全屏刷新以彻底清除残影")
|
||||||
|
else:
|
||||||
|
print("执行单次全屏刷新以清除残影")
|
||||||
|
|
||||||
|
# 创建全白缓冲区
|
||||||
|
white_buffer = bytearray(self.width * self.height // 8)
|
||||||
|
for i in range(len(white_buffer)):
|
||||||
|
white_buffer[i] = 0xFF # 全白
|
||||||
|
|
||||||
|
# 先写入全白数据
|
||||||
|
self.set_partial(0, 0, self.width, self.height)
|
||||||
|
self.write_image(0x24, white_buffer, True, True)
|
||||||
|
|
||||||
|
# 执行第一次全屏刷新
|
||||||
|
self._command(0x21,b'\x40\x00')
|
||||||
|
self._command(0x22,b'\xf7') # 使用完整刷新模式
|
||||||
|
self._command(0x20)
|
||||||
|
self.wait_until_idle()
|
||||||
|
|
||||||
|
# 如果启用双次刷新,再执行一次
|
||||||
|
if double_refresh:
|
||||||
|
print("执行第二次全屏刷新")
|
||||||
|
self._command(0x21,b'\x40\x00')
|
||||||
|
self._command(0x22,b'\xf7') # 使用完整刷新模式
|
||||||
|
self._command(0x20)
|
||||||
|
self.wait_until_idle()
|
||||||
|
|
||||||
|
# 重置刷新计数器
|
||||||
|
self.refresh_count = 0
|
||||||
|
self.force_full_refresh = False
|
||||||
|
print("全屏刷新完成")
|
||||||
|
|
||||||
|
def write_image(self, command, bitmap, mirror_x, mirror_y):
|
||||||
|
sleep_ms(1)
|
||||||
|
h = self.height
|
||||||
|
w = self.width
|
||||||
|
bpl = w // 8 # bytes per line
|
||||||
|
|
||||||
|
self._command(command)
|
||||||
|
for i in range(0, h):
|
||||||
|
for j in range(0, bpl):
|
||||||
|
idx = ((bpl-j-1) if mirror_x else j) + ((h-i-1) if mirror_y else i) * bpl
|
||||||
|
self._ndata(bitmap[idx])
|
||||||
|
|
||||||
|
def write_value(self, command, value):
|
||||||
|
sleep_ms(1)
|
||||||
|
h = self.height
|
||||||
|
w = self.width
|
||||||
|
bpl = w // 8 # bytes per line
|
||||||
|
|
||||||
|
self._command(command)
|
||||||
|
for i in range(0, h):
|
||||||
|
for j in range(0, bpl):
|
||||||
|
self._ndata(value)
|
||||||
|
|
||||||
|
# 修改显示方法,添加刷新控制逻辑
|
||||||
|
def display_frame(self, frame_buffer, partial=False, x=0, y=0, w=None, h=None, global_refresh=False):
|
||||||
|
"""显示帧缓冲区内容
|
||||||
|
|
||||||
|
参数:
|
||||||
|
frame_buffer: 要显示的帧缓冲区数据
|
||||||
|
partial: 是否使用局部刷新模式,默认为False
|
||||||
|
x: 局部刷新的起始X坐标,默认为0
|
||||||
|
y: 局部刷新的起始Y坐标,默认为0
|
||||||
|
w: 局部刷新的宽度,默认为全屏宽度
|
||||||
|
h: 局部刷新的高度,默认为全屏高度
|
||||||
|
global_refresh: 是否使用全局刷新模式,默认为False
|
||||||
|
"""
|
||||||
|
print("显示帧缓冲区")
|
||||||
|
if self.init_done==False:
|
||||||
|
self.init()
|
||||||
|
|
||||||
|
# 如果未指定宽高,则使用全屏
|
||||||
|
if w is None:
|
||||||
|
w = self.width
|
||||||
|
if h is None:
|
||||||
|
h = self.height
|
||||||
|
|
||||||
|
# 检查是否需要强制全屏刷新
|
||||||
|
need_clear_screen = self.force_full_refresh or self.refresh_count >= self.partial_refresh_limit
|
||||||
|
|
||||||
|
# 如果使用全局刷新模式,则设置全屏刷新区域
|
||||||
|
if global_refresh:
|
||||||
|
self.set_partial(0, 0, self.width, self.height)
|
||||||
|
elif need_clear_screen:
|
||||||
|
self.clear_screen()
|
||||||
|
# 设置局部刷新区域
|
||||||
|
self.set_partial(x, y, w, h)
|
||||||
|
else:
|
||||||
|
# 设置局部刷新区域
|
||||||
|
self.set_partial(x, y, w, h)
|
||||||
|
|
||||||
|
# 写入图像数据
|
||||||
|
self.write_image(0x24, frame_buffer, True, True)
|
||||||
|
|
||||||
|
# 播放等待音效 (异步)
|
||||||
|
if system_buzzer:
|
||||||
|
system_buzzer.play_process_async()
|
||||||
|
|
||||||
|
# 执行刷新
|
||||||
|
if global_refresh:
|
||||||
|
# 全局刷新模式
|
||||||
|
print("执行全局刷新模式")
|
||||||
|
self._command(0x21,b'\x40\x00')
|
||||||
|
self._command(0x22,b'\xf7') # 使用完整刷新模式
|
||||||
|
self._command(0x20)
|
||||||
|
self.wait_until_idle()
|
||||||
|
self.refresh_count = 0
|
||||||
|
print("全局刷新完成,重置计数器")
|
||||||
|
elif need_clear_screen:
|
||||||
|
# 已经通过clear_screen()执行了刷新,这里不需要再次刷新
|
||||||
|
print("已通过clear_screen完成全屏刷新,跳过重复刷新")
|
||||||
|
self.refresh_count = 0
|
||||||
|
elif partial and not self.force_full_refresh and self.refresh_count < self.partial_refresh_limit:
|
||||||
|
# 局部刷新模式
|
||||||
|
print("执行局部刷新模式")
|
||||||
|
self._command(0x21,b'\x40\x00')
|
||||||
|
self._command(0x1A, b'\x64') # 快速刷新设置
|
||||||
|
self._command(0x22,b'\xd7') # 局部刷新命令
|
||||||
|
self._command(0x20)
|
||||||
|
self.wait_until_idle()
|
||||||
|
self.refresh_count += 1
|
||||||
|
print(f"局部刷新完成,刷新计数: {self.refresh_count}/{self.partial_refresh_limit}")
|
||||||
|
else:
|
||||||
|
# 全屏刷新模式
|
||||||
|
print("执行全屏刷新模式")
|
||||||
|
self.update_full()
|
||||||
|
self.refresh_count = 0
|
||||||
|
print("全屏刷新完成,重置计数器")
|
||||||
|
|
||||||
|
# 添加强制全屏刷新的方法
|
||||||
|
def force_refresh(self):
|
||||||
|
"""强制执行下一次全屏刷新,清除所有残影"""
|
||||||
|
self.force_full_refresh = True
|
||||||
|
print("已设置强制全屏刷新标志")
|
||||||
|
|
||||||
|
# to wake call reset() or init()
|
||||||
|
def sleep(self):
|
||||||
|
self.pwr_off()
|
||||||
|
self._command(0x10, b'\x01')
|
||||||
|
self.init_done = False
|
||||||
|
self.hibernate = True
|
||||||
Reference in New Issue
Block a user