当前位置: 首页 > news >正文

【micropython】SPI触摸屏开发

背景:

最近买了几块ESP32模块,看了下mircopython支持还不错,所以买了个SPI触摸屏试试水,记录一下使用过程。

硬件相关:

SPI触摸屏

使用2.4寸屏幕,常见淘宝均可买到,驱动为ILI9341,具体参数如下图:

引脚描述:

ESP32模块

依旧轻松购买于淘宝,由于ESP32被很多家封装,因此模块各有不同,我的如下:

接口描述,网上找了个,差异点在于图中使用GIPOxx,而开发板印刷使用Dxx,例如,开发板上,D12,对应下图的GPIO12,其他的不需要关注:

接线

由于ESP32模块有两个可用SPI,而触摸屏显示和触摸都是使用SPI协议,刚好用完资源,

SPI

SCK

MOSI

MISO

CS

用途

SPI1(HSPI)

GPIO14(D14)

GPIO13(D13)

GPIO12(D12)

GPIO15(D15)

分配给触摸接口

SPI2(VSPI)

GPIO18(D18)

GPIO23(D23)

GPIO19(D19)

GPIO5(D5)

分配给显示接口

图上还会看到VSPI 和 HSPI

具体接线如下:

触摸屏

分配(ESP32引脚名)

归属

显示设备

VCC

3V3

ESP-IO

GND

GND

ESP-IO

CS

D5

SPI2

RESET

D2

ESP-IO

DC/RS

D21

ESP-IO

SDI

D23

SPI2

SCK

D18

SPI2

LED

D4

ESP-IO

SDO

D19

SPI2

触摸设备

T_CLK

D14

SPI1

T_CS

D15

SPI1

T_DIN

D13

SPI1

T_DO

D12

SPI1

T_IRQ

D33

ESP-IO

注意(不建议使用的引脚):

不建议使用或限制使用的引脚
不建议使用 Strapping引脚 ,SPI flash 引脚 以及 仅输入的引脚
Strapping 引脚
GPIO 0
GPIO 2
GPIO 4
GPIO 5 (启动时必须为高电平)
GPIO 12 (启动时必须为低电平)
GPIO 15 (启动时必须为高电平)
注意:
在硬件上要注意使用外接模块时不能将GPIO12拉高,否则将导致ESP32启动异常。还有一些GPIO在启动或重置时其状态更改为高或者输出PWM信号,在使用时需要注意。
集成在ESP-WROOM-32 的 SPI flash 引脚
GPIO 6 到 GPIO 11 在一些 ESP32 开发板中公开。但是,这些引脚连接到 ESP-WROOM-32 芯片上的集成 SPI 闪存,不推荐用于其他用途。所以,不要在你的项目中使用这些引脚:
GPIO 6 (SCK/CLK)
GPIO 7 (SDO/SD0)
GPIO 8 (SDI/SD1)
GPIO 9 (SHD/SD2)
GPIO 10 (SWP/SD3)
GPIO 11 (CSC/CMD)
仅输入引脚
GPIO 34 到 39 是 GPI – 仅输入引脚。这些引脚没有内部上拉或下拉电阻。它们不能用作输出,因此只能将这些引脚用作输入:
GPIO 34
GPIO 35
GPIO 36
GPIO 39
这些引脚都是ESP32用于引导加载程序或者烧录模式/在大多数内置USB/Serial的开发板上,不需要担心这些引脚的状态,开发板会把这些引脚设置为正确的状态,以便使用烧录或启动模式。
但是,如果你有外设连接到这些引脚上,当你在尝试上传新代码、用新固件烧写ESP32或重置电路板时可能会遇到麻烦,例如不明原因的错误和失败。可能是因为这些外设阻止ESP32进入正确的模式。
所以以上的引脚 不建议在项目中使用。

软件相关

目录结构

其中core/screen 文件夹,lib/ili9341.py 和 lib/xpt2046.py 以及main.py是我们本次测试文件.

效果

显示测试:

触摸测试:

代码

lib/ili9341.py

"""ILI9341 LCD/Touch module."""
from time import sleep
from math import cos, sin, pi, radians
from sys import implementation
from framebuf import FrameBuffer, RGB565  # type: ignore
import ustruct  # type: ignoredef color565(r, g, b):"""Return RGB565 color value.Args:r (int): Red value.g (int): Green value.b (int): Blue value."""return (r & 0xf8) << 8 | (g & 0xfc) << 3 | b >> 3class Display(object):"""Serial interface for 16-bit color (5-6-5 RGB) IL9341 display.Note:  All coordinates are zero based."""# Command constants from ILI9341 datasheetNOP = const(0x00)  # No-opSWRESET = const(0x01)  # Software resetRDDID = const(0x04)  # Read display ID infoRDDST = const(0x09)  # Read display statusSLPIN = const(0x10)  # Enter sleep modeSLPOUT = const(0x11)  # Exit sleep modePTLON = const(0x12)  # Partial mode onNORON = const(0x13)  # Normal display mode onRDMODE = const(0x0A)  # Read display power modeRDMADCTL = const(0x0B)  # Read display MADCTLRDPIXFMT = const(0x0C)  # Read display pixel formatRDIMGFMT = const(0x0D)  # Read display image formatRDSELFDIAG = const(0x0F)  # Read display self-diagnosticINVOFF = const(0x20)  # Display inversion offINVON = const(0x21)  # Display inversion onGAMMASET = const(0x26)  # Gamma setDISPLAY_OFF = const(0x28)  # Display offDISPLAY_ON = const(0x29)  # Display onSET_COLUMN = const(0x2A)  # Column address setSET_PAGE = const(0x2B)  # Page address setWRITE_RAM = const(0x2C)  # Memory writeREAD_RAM = const(0x2E)  # Memory readPTLAR = const(0x30)  # Partial areaVSCRDEF = const(0x33)  # Vertical scrolling definitionMADCTL = const(0x36)  # Memory access controlVSCRSADD = const(0x37)  # Vertical scrolling start addressPIXFMT = const(0x3A)  # COLMOD: Pixel format setWRITE_DISPLAY_BRIGHTNESS = const(0x51)  # Brightness hardware dependent!READ_DISPLAY_BRIGHTNESS = const(0x52)WRITE_CTRL_DISPLAY = const(0x53)READ_CTRL_DISPLAY = const(0x54)WRITE_CABC = const(0x55)  # Write Content Adaptive Brightness ControlREAD_CABC = const(0x56)  # Read Content Adaptive Brightness ControlWRITE_CABC_MINIMUM = const(0x5E)  # Write CABC Minimum BrightnessREAD_CABC_MINIMUM = const(0x5F)  # Read CABC Minimum BrightnessFRMCTR1 = const(0xB1)  # Frame rate control (In normal mode/full colors)FRMCTR2 = const(0xB2)  # Frame rate control (In idle mode/8 colors)FRMCTR3 = const(0xB3)  # Frame rate control (In partial mode/full colors)INVCTR = const(0xB4)  # Display inversion controlDFUNCTR = const(0xB6)  # Display function controlPWCTR1 = const(0xC0)  # Power control 1PWCTR2 = const(0xC1)  # Power control 2PWCTRA = const(0xCB)  # Power control APWCTRB = const(0xCF)  # Power control BVMCTR1 = const(0xC5)  # VCOM control 1VMCTR2 = const(0xC7)  # VCOM control 2RDID1 = const(0xDA)  # Read ID 1RDID2 = const(0xDB)  # Read ID 2RDID3 = const(0xDC)  # Read ID 3RDID4 = const(0xDD)  # Read ID 4GMCTRP1 = const(0xE0)  # Positive gamma correctionGMCTRN1 = const(0xE1)  # Negative gamma correctionDTCA = const(0xE8)  # Driver timing control ADTCB = const(0xEA)  # Driver timing control BPOSC = const(0xED)  # Power on sequence controlENABLE3G = const(0xF2)  # Enable 3 gamma controlPUMPRC = const(0xF7)  # Pump ratio controlROTATE = {0: 0x88,90: 0xE8,180: 0x48,270: 0x28}def __init__(self, spi, cs, dc, rst,width=240, height=320, rotation=0):"""Initialize OLED.Args:spi (Class Spi):  SPI interface for OLEDcs (Class Pin):  Chip select pindc (Class Pin):  Data/Command pinrst (Class Pin):  Reset pinwidth (Optional int): Screen width (default 240)height (Optional int): Screen height (default 320)rotation (Optional int): Rotation must be 0 default, 90. 180 or 270"""self.spi = spiself.cs = csself.dc = dcself.rst = rstself.width = widthself.height = heightif rotation not in self.ROTATE.keys():raise RuntimeError('Rotation must be 0, 90, 180 or 270.')else:self.rotation = self.ROTATE[rotation]# Initialize GPIO pins and set implementation specific methodsif implementation.name == 'circuitpython':self.cs.switch_to_output(value=True)self.dc.switch_to_output(value=False)self.rst.switch_to_output(value=True)self.reset = self.reset_cpyself.write_cmd = self.write_cmd_cpyself.write_data = self.write_data_cpyelse:self.cs.init(self.cs.OUT, value=1)self.dc.init(self.dc.OUT, value=0)self.rst.init(self.rst.OUT, value=1)self.reset = self.reset_mpyself.write_cmd = self.write_cmd_mpyself.write_data = self.write_data_mpyself.reset()# Send initialization commandsself.write_cmd(self.SWRESET)  # Software resetsleep(.1)self.write_cmd(self.PWCTRB, 0x00, 0xC1, 0x30)  # Pwr ctrl Bself.write_cmd(self.POSC, 0x64, 0x03, 0x12, 0x81)  # Pwr on seq. ctrlself.write_cmd(self.DTCA, 0x85, 0x00, 0x78)  # Driver timing ctrl Aself.write_cmd(self.PWCTRA, 0x39, 0x2C, 0x00, 0x34, 0x02)  # Pwr ctrl Aself.write_cmd(self.PUMPRC, 0x20)  # Pump ratio controlself.write_cmd(self.DTCB, 0x00, 0x00)  # Driver timing ctrl Bself.write_cmd(self.PWCTR1, 0x23)  # Pwr ctrl 1self.write_cmd(self.PWCTR2, 0x10)  # Pwr ctrl 2self.write_cmd(self.VMCTR1, 0x3E, 0x28)  # VCOM ctrl 1self.write_cmd(self.VMCTR2, 0x86)  # VCOM ctrl 2self.write_cmd(self.MADCTL, self.rotation)  # Memory access ctrlself.write_cmd(self.VSCRSADD, 0x00)  # Vertical scrolling start addressself.write_cmd(self.PIXFMT, 0x55)  # COLMOD: Pixel formatself.write_cmd(self.FRMCTR1, 0x00, 0x18)  # Frame rate ctrlself.write_cmd(self.DFUNCTR, 0x08, 0x82, 0x27)self.write_cmd(self.ENABLE3G, 0x00)  # Enable 3 gamma ctrlself.write_cmd(self.GAMMASET, 0x01)  # Gamma curve selectedself.write_cmd(self.GMCTRP1, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E,0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00)self.write_cmd(self.GMCTRN1, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31,0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F)self.write_cmd(self.SLPOUT)  # Exit sleepsleep(.1)self.write_cmd(self.DISPLAY_ON)  # Display onsleep(.1)self.clear()def block(self, x0, y0, x1, y1, data):"""Write a block of data to display.Args:x0 (int):  Starting X position.y0 (int):  Starting Y position.x1 (int):  Ending X position.y1 (int):  Ending Y position.data (bytes): Data buffer to write."""self.write_cmd(self.SET_COLUMN, *ustruct.pack(">HH", x0, x1))self.write_cmd(self.SET_PAGE, *ustruct.pack(">HH", y0, y1))self.write_cmd(self.WRITE_RAM)self.write_data(data)def cleanup(self):"""Clean up resources."""self.clear()self.display_off()self.spi.deinit()print('display off')def clear(self, color=0):"""Clear display.Args:color (Optional int): RGB565 color value (Default: 0 = Black)."""w = self.widthh = self.height# Clear display in 1024 byte blocksif color:line = color.to_bytes(2, 'big') * (w * 8)else:line = bytearray(w * 16)for y in range(0, h, 8):self.block(0, y, w - 1, y + 7, line)def display_off(self):"""Turn display off."""self.write_cmd(self.DISPLAY_OFF)def display_on(self):"""Turn display on."""self.write_cmd(self.DISPLAY_ON)def draw_circle(self, x0, y0, r, color):"""Draw a circle.Args:x0 (int): X coordinate of center point.y0 (int): Y coordinate of center point.r (int): Radius.color (int): RGB565 color value."""f = 1 - rdx = 1dy = -r - rx = 0y = rself.draw_pixel(x0, y0 + r, color)self.draw_pixel(x0, y0 - r, color)self.draw_pixel(x0 + r, y0, color)self.draw_pixel(x0 - r, y0, color)while x < y:if f >= 0:y -= 1dy += 2f += dyx += 1dx += 2f += dxself.draw_pixel(x0 + x, y0 + y, color)self.draw_pixel(x0 - x, y0 + y, color)self.draw_pixel(x0 + x, y0 - y, color)self.draw_pixel(x0 - x, y0 - y, color)self.draw_pixel(x0 + y, y0 + x, color)self.draw_pixel(x0 - y, y0 + x, color)self.draw_pixel(x0 + y, y0 - x, color)self.draw_pixel(x0 - y, y0 - x, color)def draw_ellipse(self, x0, y0, a, b, color):"""Draw an ellipse.Args:x0, y0 (int): Coordinates of center point.a (int): Semi axis horizontal.b (int): Semi axis vertical.color (int): RGB565 color value.Note:The center point is the center of the x0,y0 pixel.Since pixels are not divisible, the axes are integer roundedup to complete on a full pixel.  Therefore the major andminor axes are increased by 1."""a2 = a * ab2 = b * btwoa2 = a2 + a2twob2 = b2 + b2x = 0y = bpx = 0py = twoa2 * y# Plot initial pointsself.draw_pixel(x0 + x, y0 + y, color)self.draw_pixel(x0 - x, y0 + y, color)self.draw_pixel(x0 + x, y0 - y, color)self.draw_pixel(x0 - x, y0 - y, color)# Region 1p = round(b2 - (a2 * b) + (0.25 * a2))while px < py:x += 1px += twob2if p < 0:p += b2 + pxelse:y -= 1py -= twoa2p += b2 + px - pyself.draw_pixel(x0 + x, y0 + y, color)self.draw_pixel(x0 - x, y0 + y, color)self.draw_pixel(x0 + x, y0 - y, color)self.draw_pixel(x0 - x, y0 - y, color)# Region 2p = round(b2 * (x + 0.5) * (x + 0.5) +a2 * (y - 1) * (y - 1) - a2 * b2)while y > 0:y -= 1py -= twoa2if p > 0:p += a2 - pyelse:x += 1px += twob2p += a2 - py + pxself.draw_pixel(x0 + x, y0 + y, color)self.draw_pixel(x0 - x, y0 + y, color)self.draw_pixel(x0 + x, y0 - y, color)self.draw_pixel(x0 - x, y0 - y, color)def draw_hline(self, x, y, w, color):"""Draw a horizontal line.Args:x (int): Starting X position.y (int): Starting Y position.w (int): Width of line.color (int): RGB565 color value."""if self.is_off_grid(x, y, x + w - 1, y):returnline = color.to_bytes(2, 'big') * wself.block(x, y, x + w - 1, y, line)def draw_image(self, path, x=0, y=0, w=320, h=240):"""Draw image from flash.Args:path (string): Image file path.x (int): X coordinate of image left.  Default is 0.y (int): Y coordinate of image top.  Default is 0.w (int): Width of image.  Default is 320.h (int): Height of image.  Default is 240."""x2 = x + w - 1y2 = y + h - 1if self.is_off_grid(x, y, x2, y2):returnwith open(path, "rb") as f:chunk_height = 1024 // wchunk_count, remainder = divmod(h, chunk_height)chunk_size = chunk_height * w * 2chunk_y = yif chunk_count:for c in range(0, chunk_count):buf = f.read(chunk_size)self.block(x, chunk_y,x2, chunk_y + chunk_height - 1,buf)chunk_y += chunk_heightif remainder:buf = f.read(remainder * w * 2)self.block(x, chunk_y,x2, chunk_y + remainder - 1,buf)def draw_letter(self, x, y, letter, font, color, background=0,landscape=False):"""Draw a letter.Args:x (int): Starting X position.y (int): Starting Y position.letter (string): Letter to draw.font (XglcdFont object): Font.color (int): RGB565 color value.background (int): RGB565 background color (default: black).landscape (bool): Orientation (default: False = portrait)"""buf, w, h = font.get_letter(letter, color, background, landscape)# Check for errors (Font could be missing specified letter)if w == 0:return w, hif landscape:y -= wif self.is_off_grid(x, y, x + h - 1, y + w - 1):return 0, 0self.block(x, y,x + h - 1, y + w - 1,buf)else:if self.is_off_grid(x, y, x + w - 1, y + h - 1):return 0, 0self.block(x, y,x + w - 1, y + h - 1,buf)return w, hdef draw_line(self, x1, y1, x2, y2, color):"""Draw a line using Bresenham's algorithm.Args:x1, y1 (int): Starting coordinates of the linex2, y2 (int): Ending coordinates of the linecolor (int): RGB565 color value."""# Check for horizontal lineif y1 == y2:if x1 > x2:x1, x2 = x2, x1self.draw_hline(x1, y1, x2 - x1 + 1, color)return# Check for vertical lineif x1 == x2:if y1 > y2:y1, y2 = y2, y1self.draw_vline(x1, y1, y2 - y1 + 1, color)return# Confirm coordinates in boundaryif self.is_off_grid(min(x1, x2), min(y1, y2),max(x1, x2), max(y1, y2)):return# Changes in x, ydx = x2 - x1dy = y2 - y1# Determine how steep the line isis_steep = abs(dy) > abs(dx)# Rotate lineif is_steep:x1, y1 = y1, x1x2, y2 = y2, x2# Swap start and end points if necessaryif x1 > x2:x1, x2 = x2, x1y1, y2 = y2, y1# Recalculate differentialsdx = x2 - x1dy = y2 - y1# Calculate errorerror = dx >> 1ystep = 1 if y1 < y2 else -1y = y1for x in range(x1, x2 + 1):# Had to reverse HW ????if not is_steep:self.draw_pixel(x, y, color)else:self.draw_pixel(y, x, color)error -= abs(dy)if error < 0:y += ysteperror += dxdef draw_lines(self, coords, color):"""Draw multiple lines.Args:coords ([[int, int],...]): Line coordinate X, Y pairscolor (int): RGB565 color value."""# Starting pointx1, y1 = coords[0]# Iterate through coordinatesfor i in range(1, len(coords)):x2, y2 = coords[i]self.draw_line(x1, y1, x2, y2, color)x1, y1 = x2, y2def draw_pixel(self, x, y, color):"""Draw a single pixel.Args:x (int): X position.y (int): Y position.color (int): RGB565 color value."""if self.is_off_grid(x, y, x, y):returnself.block(x, y, x, y, color.to_bytes(2, 'big'))def draw_polygon(self, sides, x0, y0, r, color, rotate=0):"""Draw an n-sided regular polygon.Args:sides (int): Number of polygon sides.x0, y0 (int): Coordinates of center point.r (int): Radius.color (int): RGB565 color value.rotate (Optional float): Rotation in degrees relative to origin.Note:The center point is the center of the x0,y0 pixel.Since pixels are not divisible, the radius is integer roundedup to complete on a full pixel.  Therefore diameter = 2 x r + 1."""coords = []theta = radians(rotate)n = sides + 1for s in range(n):t = 2.0 * pi * s / sides + thetacoords.append([int(r * cos(t) + x0), int(r * sin(t) + y0)])# Cast to python float first to fix rounding errorsself.draw_lines(coords, color=color)def draw_rectangle(self, x, y, w, h, color):"""Draw a rectangle.Args:x (int): Starting X position.y (int): Starting Y position.w (int): Width of rectangle.h (int): Height of rectangle.color (int): RGB565 color value."""x2 = x + w - 1y2 = y + h - 1self.draw_hline(x, y, w, color)self.draw_hline(x, y2, w, color)self.draw_vline(x, y, h, color)self.draw_vline(x2, y, h, color)def draw_sprite(self, buf, x, y, w, h):"""Draw a sprite (optimized for horizontal drawing).Args:buf (bytearray): Buffer to draw.x (int): Starting X position.y (int): Starting Y position.w (int): Width of drawing.h (int): Height of drawing."""x2 = x + w - 1y2 = y + h - 1if self.is_off_grid(x, y, x2, y2):returnself.block(x, y, x2, y2, buf)def draw_text(self, x, y, text, font, color,  background=0,landscape=False, spacing=1):"""Draw text.Args:x (int): Starting X position.y (int): Starting Y position.text (string): Text to draw.font (XglcdFont object): Font.color (int): RGB565 color value.background (int): RGB565 background color (default: black).landscape (bool): Orientation (default: False = portrait)spacing (int): Pixels between letters (default: 1)"""for letter in text:# Get letter array and letter dimensionsw, h = self.draw_letter(x, y, letter, font, color, background,landscape)# Stop on errorif w == 0 or h == 0:print('Invalid width {0} or height {1}'.format(w, h))returnif landscape:# Fill in spacingif spacing:self.fill_hrect(x, y - w - spacing, h, spacing, background)# Position y for next lettery -= (w + spacing)else:# Fill in spacingif spacing:self.fill_hrect(x + w, y, spacing, h, background)# Position x for next letterx += (w + spacing)# # Fill in spacing# if spacing:#     self.fill_vrect(x + w, y, spacing, h, background)# # Position x for next letter# x += w + spacingdef draw_text8x8(self, x, y, text, color,  background=0,rotate=0):"""Draw text using built-in MicroPython 8x8 bit font.Args:x (int): Starting X position.y (int): Starting Y position.text (string): Text to draw.color (int): RGB565 color value.background (int): RGB565 background color (default: black).rotate(int): 0, 90, 180, 270"""w = len(text) * 8h = 8# Confirm coordinates in boundaryif self.is_off_grid(x, y, x + 7, y + 7):return# Rearrange colorr = (color & 0xF800) >> 8g = (color & 0x07E0) >> 3b = (color & 0x1F) << 3buf = bytearray(w * 16)fbuf = FrameBuffer(buf, w, h, RGB565)if background != 0:bg_r = (background & 0xF800) >> 8bg_g = (background & 0x07E0) >> 3bg_b = (background & 0x1F) << 3fbuf.fill(color565(bg_b, bg_r, bg_g))fbuf.text(text, 0, 0, color565(b, r, g))if rotate == 0:self.block(x, y, x + w - 1, y + (h - 1), buf)elif rotate == 90:buf2 = bytearray(w * 16)fbuf2 = FrameBuffer(buf2, h, w, RGB565)for y1 in range(h):for x1 in range(w):fbuf2.pixel(y1, x1,fbuf.pixel(x1, (h - 1) - y1))self.block(x, y, x + (h - 1), y + w - 1, buf2)elif rotate == 180:buf2 = bytearray(w * 16)fbuf2 = FrameBuffer(buf2, w, h, RGB565)for y1 in range(h):for x1 in range(w):fbuf2.pixel(x1, y1,fbuf.pixel((w - 1) - x1, (h - 1) - y1))self.block(x, y, x + w - 1, y + (h - 1), buf2)elif rotate == 270:buf2 = bytearray(w * 16)fbuf2 = FrameBuffer(buf2, h, w, RGB565)for y1 in range(h):for x1 in range(w):fbuf2.pixel(y1, x1,fbuf.pixel((w - 1) - x1, y1))self.block(x, y, x + (h - 1), y + w - 1, buf2)def draw_vline(self, x, y, h, color):"""Draw a vertical line.Args:x (int): Starting X position.y (int): Starting Y position.h (int): Height of line.color (int): RGB565 color value."""# Confirm coordinates in boundaryif self.is_off_grid(x, y, x, y + h - 1):returnline = color.to_bytes(2, 'big') * hself.block(x, y, x, y + h - 1, line)def fill_circle(self, x0, y0, r, color):"""Draw a filled circle.Args:x0 (int): X coordinate of center point.y0 (int): Y coordinate of center point.r (int): Radius.color (int): RGB565 color value."""f = 1 - rdx = 1dy = -r - rx = 0y = rself.draw_vline(x0, y0 - r, 2 * r + 1, color)while x < y:if f >= 0:y -= 1dy += 2f += dyx += 1dx += 2f += dxself.draw_vline(x0 + x, y0 - y, 2 * y + 1, color)self.draw_vline(x0 - x, y0 - y, 2 * y + 1, color)self.draw_vline(x0 - y, y0 - x, 2 * x + 1, color)self.draw_vline(x0 + y, y0 - x, 2 * x + 1, color)def fill_ellipse(self, x0, y0, a, b, color):"""Draw a filled ellipse.Args:x0, y0 (int): Coordinates of center point.a (int): Semi axis horizontal.b (int): Semi axis vertical.color (int): RGB565 color value.Note:The center point is the center of the x0,y0 pixel.Since pixels are not divisible, the axes are integer roundedup to complete on a full pixel.  Therefore the major andminor axes are increased by 1."""a2 = a * ab2 = b * btwoa2 = a2 + a2twob2 = b2 + b2x = 0y = bpx = 0py = twoa2 * y# Plot initial pointsself.draw_line(x0, y0 - y, x0, y0 + y, color)# Region 1p = round(b2 - (a2 * b) + (0.25 * a2))while px < py:x += 1px += twob2if p < 0:p += b2 + pxelse:y -= 1py -= twoa2p += b2 + px - pyself.draw_line(x0 + x, y0 - y, x0 + x, y0 + y, color)self.draw_line(x0 - x, y0 - y, x0 - x, y0 + y, color)# Region 2p = round(b2 * (x + 0.5) * (x + 0.5) +a2 * (y - 1) * (y - 1) - a2 * b2)while y > 0:y -= 1py -= twoa2if p > 0:p += a2 - pyelse:x += 1px += twob2p += a2 - py + pxself.draw_line(x0 + x, y0 - y, x0 + x, y0 + y, color)self.draw_line(x0 - x, y0 - y, x0 - x, y0 + y, color)def fill_hrect(self, x, y, w, h, color):"""Draw a filled rectangle (optimized for horizontal drawing).Args:x (int): Starting X position.y (int): Starting Y position.w (int): Width of rectangle.h (int): Height of rectangle.color (int): RGB565 color value."""if self.is_off_grid(x, y, x + w - 1, y + h - 1):returnchunk_height = 1024 // wchunk_count, remainder = divmod(h, chunk_height)chunk_size = chunk_height * wchunk_y = yif chunk_count:buf = color.to_bytes(2, 'big') * chunk_sizefor c in range(0, chunk_count):self.block(x, chunk_y,x + w - 1, chunk_y + chunk_height - 1,buf)chunk_y += chunk_heightif remainder:buf = color.to_bytes(2, 'big') * remainder * wself.block(x, chunk_y,x + w - 1, chunk_y + remainder - 1,buf)def fill_rectangle(self, x, y, w, h, color):"""Draw a filled rectangle.Args:x (int): Starting X position.y (int): Starting Y position.w (int): Width of rectangle.h (int): Height of rectangle.color (int): RGB565 color value."""if self.is_off_grid(x, y, x + w - 1, y + h - 1):returnif w > h:self.fill_hrect(x, y, w, h, color)else:self.fill_vrect(x, y, w, h, color)def fill_polygon(self, sides, x0, y0, r, color, rotate=0):"""Draw a filled n-sided regular polygon.Args:sides (int): Number of polygon sides.x0, y0 (int): Coordinates of center point.r (int): Radius.color (int): RGB565 color value.rotate (Optional float): Rotation in degrees relative to origin.Note:The center point is the center of the x0,y0 pixel.Since pixels are not divisible, the radius is integer roundedup to complete on a full pixel.  Therefore diameter = 2 x r + 1."""# Determine side coordinatescoords = []theta = radians(rotate)n = sides + 1for s in range(n):t = 2.0 * pi * s / sides + thetacoords.append([int(r * cos(t) + x0), int(r * sin(t) + y0)])# Starting pointx1, y1 = coords[0]# Minimum Maximum X dictxdict = {y1: [x1, x1]}# Iterate through coordinatesfor row in coords[1:]:x2, y2 = rowxprev, yprev = x2, y2# Calculate perimeter# Check for horizontal sideif y1 == y2:if x1 > x2:x1, x2 = x2, x1if y1 in xdict:xdict[y1] = [min(x1, xdict[y1][0]), max(x2, xdict[y1][1])]else:xdict[y1] = [x1, x2]x1, y1 = xprev, yprevcontinue# Non horizontal side# Changes in x, ydx = x2 - x1dy = y2 - y1# Determine how steep the line isis_steep = abs(dy) > abs(dx)# Rotate lineif is_steep:x1, y1 = y1, x1x2, y2 = y2, x2# Swap start and end points if necessaryif x1 > x2:x1, x2 = x2, x1y1, y2 = y2, y1# Recalculate differentialsdx = x2 - x1dy = y2 - y1# Calculate errorerror = dx >> 1ystep = 1 if y1 < y2 else -1y = y1# Calcualte minimum and maximum x valuesfor x in range(x1, x2 + 1):if is_steep:if x in xdict:xdict[x] = [min(y, xdict[x][0]), max(y, xdict[x][1])]else:xdict[x] = [y, y]else:if y in xdict:xdict[y] = [min(x, xdict[y][0]), max(x, xdict[y][1])]else:xdict[y] = [x, x]error -= abs(dy)if error < 0:y += ysteperror += dxx1, y1 = xprev, yprev# Fill polygonfor y, x in xdict.items():self.draw_hline(x[0], y, x[1] - x[0] + 2, color)def fill_vrect(self, x, y, w, h, color):"""Draw a filled rectangle (optimized for vertical drawing).Args:x (int): Starting X position.y (int): Starting Y position.w (int): Width of rectangle.h (int): Height of rectangle.color (int): RGB565 color value."""if self.is_off_grid(x, y, x + w - 1, y + h - 1):returnchunk_width = 1024 // hchunk_count, remainder = divmod(w, chunk_width)chunk_size = chunk_width * hchunk_x = xif chunk_count:buf = color.to_bytes(2, 'big') * chunk_sizefor c in range(0, chunk_count):self.block(chunk_x, y,chunk_x + chunk_width - 1, y + h - 1,buf)chunk_x += chunk_widthif remainder:buf = color.to_bytes(2, 'big') * remainder * hself.block(chunk_x, y,chunk_x + remainder - 1, y + h - 1,buf)def is_off_grid(self, xmin, ymin, xmax, ymax):"""Check if coordinates extend past display boundaries.Args:xmin (int): Minimum horizontal pixel.ymin (int): Minimum vertical pixel.xmax (int): Maximum horizontal pixel.ymax (int): Maximum vertical pixel.Returns:boolean: False = Coordinates OK, True = Error."""if xmin < 0:print('x-coordinate: {0} below minimum of 0.'.format(xmin))return Trueif ymin < 0:print('y-coordinate: {0} below minimum of 0.'.format(ymin))return Trueif xmax >= self.width:print('x-coordinate: {0} above maximum of {1}.'.format(xmax, self.width - 1))return Trueif ymax >= self.height:print('y-coordinate: {0} above maximum of {1}.'.format(ymax, self.height - 1))return Truereturn Falsedef load_sprite(self, path, w, h):"""Load sprite image.Args:path (string): Image file path.w (int): Width of image.h (int): Height of image.Notes:w x h cannot exceed 2048"""buf_size = w * h * 2with open(path, "rb") as f:return f.read(buf_size)def reset_cpy(self):"""Perform reset: Low=initialization, High=normal operation.Notes: CircuitPython implemntation"""self.rst.value = Falsesleep(.05)self.rst.value = Truesleep(.05)def reset_mpy(self):"""Perform reset: Low=initialization, High=normal operation.Notes: MicroPython implemntation"""self.rst(0)sleep(.05)self.rst(1)sleep(.05)def scroll(self, y):"""Scroll display vertically.Args:y (int): Number of pixels to scroll display."""self.write_cmd(self.VSCRSADD, y >> 8, y & 0xFF)def set_scroll(self, top, bottom):"""Set the height of the top and bottom scroll margins.Args:top (int): Height of top scroll marginbottom (int): Height of bottom scroll margin"""if top + bottom <= self.height:middle = self.height - (top + bottom)print(top, middle, bottom)self.write_cmd(self.VSCRDEF,top >> 8,top & 0xFF,middle >> 8,middle & 0xFF,bottom >> 8,bottom & 0xFF)def sleep(self, enable=True):"""Enters or exits sleep mode.Args:enable (bool): True (default)=Enter sleep mode, False=Exit sleep"""if enable:self.write_cmd(self.SLPIN)else:self.write_cmd(self.SLPOUT)def write_cmd_mpy(self, command, *args):"""Write command to OLED (MicroPython).Args:command (byte): ILI9341 command code.*args (optional bytes): Data to transmit."""self.dc(0)self.cs(0)self.spi.write(bytearray([command]))self.cs(1)# Handle any passed dataif len(args) > 0:self.write_data(bytearray(args))def write_cmd_cpy(self, command, *args):"""Write command to OLED (CircuitPython).Args:command (byte): ILI9341 command code.*args (optional bytes): Data to transmit."""self.dc.value = Falseself.cs.value = False# Confirm SPI locked before writingwhile not self.spi.try_lock():passself.spi.write(bytearray([command]))self.spi.unlock()self.cs.value = True# Handle any passed dataif len(args) > 0:self.write_data(bytearray(args))def write_data_mpy(self, data):"""Write data to OLED (MicroPython).Args:data (bytes): Data to transmit."""self.dc(1)self.cs(0)self.spi.write(data)self.cs(1)def write_data_cpy(self, data):"""Write data to OLED (CircuitPython).Args:data (bytes): Data to transmit."""self.dc.value = Trueself.cs.value = False# Confirm SPI locked before writingwhile not self.spi.try_lock():passself.spi.write(data)self.spi.unlock()self.cs.value = True

lib/xpt2046.py

"""XPT2046 Touch module."""
from time import sleepclass Touch(object):"""Serial interface for XPT2046 Touch Screen Controller."""# Command constants from ILI9341 datasheetGET_X = const(0b11010000)  # X positionGET_Y = const(0b10010000)  # Y positionGET_Z1 = const(0b10110000)  # Z1 positionGET_Z2 = const(0b11000000)  # Z2 positionGET_TEMP0 = const(0b10000000)  # Temperature 0GET_TEMP1 = const(0b11110000)  # Temperature 1GET_BATTERY = const(0b10100000)  # Battery monitorGET_AUX = const(0b11100000)  # Auxiliary input to ADCdef __init__(self, spi, cs, int_pin=None, int_handler=None,width=240, height=320,x_min=100, x_max=1962, y_min=100, y_max=1900):"""Initialize touch screen controller.Args:spi (Class Spi):  SPI interface for OLEDcs (Class Pin):  Chip select pinint_pin (Class Pin):  Touch controller interrupt pinint_handler (function): Handler for screen interruptwidth (int): Width of LCD screenheight (int): Height of LCD screenx_min (int): Minimum x coordinatex_max (int): Maximum x coordinatey_min (int): Minimum Y coordinatey_max (int): Maximum Y coordinate"""self.spi = spiself.cs = csself.cs.init(self.cs.OUT, value=1)self.rx_buf = bytearray(3)  # Receive bufferself.tx_buf = bytearray(3)  # Transmit bufferself.width = widthself.height = height# Set calibrationself.x_min = x_minself.x_max = x_maxself.y_min = y_minself.y_max = y_maxself.x_multiplier = width / (x_max - x_min)self.x_add = x_min * -self.x_multiplierself.y_multiplier = height / (y_max - y_min)self.y_add = y_min * -self.y_multiplierif int_pin is not None:self.int_pin = int_pinself.int_pin.init(int_pin.IN)self.int_handler = int_handlerself.int_locked = Falseint_pin.irq(trigger=int_pin.IRQ_FALLING | int_pin.IRQ_RISING,handler=self.int_press)def get_touch(self):"""Take multiple samples to get accurate touch reading."""timeout = 2  # set timeout to 2 secondsconfidence = 5buff = [[0, 0] for x in range(confidence)]buf_length = confidence  # Require a confidence of 5 good samplesbuffptr = 0  # Track current buffer positionnsamples = 0  # Count sampleswhile timeout > 0:if nsamples == buf_length:meanx = sum([c[0] for c in buff]) // buf_lengthmeany = sum([c[1] for c in buff]) // buf_lengthdev = sum([(c[0] - meanx)**2 +(c[1] - meany)**2 for c in buff]) / buf_lengthif dev <= 50:  # Deviation should be under margin of 50return self.normalize(meanx, meany)# get a new valuesample = self.raw_touch()  # get a touchif sample is None:nsamples = 0    # Invalidate buffelse:buff[buffptr] = sample  # put in buffbuffptr = (buffptr + 1) % buf_length  # Incr, until rollovernsamples = min(nsamples + 1, buf_length)  # Incr. until maxsleep(.05)timeout -= .05return Nonedef int_press(self, pin):"""Send X,Y values to passed interrupt handler."""if not pin.value() and not self.int_locked:self.int_locked = True  # Lock Interruptbuff = self.raw_touch()if buff is not None:x, y = self.normalize(*buff)self.int_handler(x, y)sleep(.1)  # Debounce falling edgeelif pin.value() and self.int_locked:sleep(.1)  # Debounce rising edgeself.int_locked = False  # Unlock interruptdef normalize(self, x, y):"""Normalize mean X,Y values to match LCD screen."""x = int(self.x_multiplier * x + self.x_add)y = int(self.y_multiplier * y + self.y_add)return x, ydef raw_touch(self):"""Read raw X,Y touch values.Returns:tuple(int, int): X, Y"""x = self.send_command(self.GET_X)y = self.send_command(self.GET_Y)if self.x_min <= x <= self.x_max and self.y_min <= y <= self.y_max:return (x, y)else:return Nonedef send_command(self, command):"""Write command to XT2046 (MicroPython).Args:command (byte): XT2046 command code.Returns:int: 12 bit response"""self.tx_buf[0] = commandself.cs(0)self.spi.write_readinto(self.tx_buf, self.rx_buf)self.cs(1)return (self.rx_buf[1] << 4) | (self.rx_buf[2] >> 4)

core/screen/TLedCfg.py


class TLedConfig:def __init__(self) -> None:self.CS = 15    # 片选, 低电平使能self.RESET = 2  # 低电平复位self.DC = 21    # 液晶屏寄存器/数据选择信号,0:寄存器,1:数据self.SDI = 23   # MOSI 写self.SCK = 18   # 时钟self.LED = 4    # 背光控制,高电平点亮self.SDO = 19   # MISO 读self.T_CLK = 14 # 触摸时钟self.T_CS =  27 # 片选,低电平使能self.T_DIN = 13 # 总线输入,接MOSIself.T_DO  = 12 # 总线输出,接MISOself.T_IRQ = 33 # 中断,检测到触摸时为低电平

core/screen/test.py

from lib.ili9341 import Display, color565
from lib.xpt2046 import Touch
from machine import Pin, SPI, idle
from core.screen.TLedCfg import TLedConfig
from time import sleepdef ScreenTest():ledCfg = TLedConfig()power = Pin(ledCfg.LED, Pin.OUT)power.value(1)spi = SPI(2, baudrate=40000000, sck=Pin(ledCfg.SCK), mosi=Pin(ledCfg.SDI))display = Display(spi, dc=Pin(ledCfg.DC), cs=Pin(ledCfg.CS), rst=Pin(ledCfg.RESET))display.clear(color565(64, 0, 255))sleep(1)display.clear()display.draw_hline(10, 319, 229, color565(255, 0, 255))sleep(1)display.draw_vline(10, 0, 319, color565(0, 255, 255))sleep(1)display.fill_hrect(23, 50, 30, 75, color565(255, 255, 255))sleep(1)display.draw_hline(0, 0, 222, color565(255, 0, 0))sleep(1)display.draw_line(127, 0, 64, 127, color565(255, 255, 0))sleep(2)display.clear()coords = [[0, 63], [78, 80], [122, 92], [50, 50], [78, 15], [0, 63]]display.draw_lines(coords, color565(0, 255, 255))sleep(1)display.clear()display.fill_polygon(7, 120, 120, 100, color565(0, 255, 0))sleep(1)display.fill_rectangle(0, 0, 15, 227, color565(255, 0, 0))sleep(1)display.clear()display.fill_rectangle(0, 0, 163, 163, color565(128, 128, 255))sleep(1)display.draw_rectangle(0, 64, 163, 163, color565(255, 0, 255))sleep(1)display.fill_rectangle(64, 0, 163, 163, color565(128, 0, 255))sleep(1)display.draw_polygon(3, 120, 286, 30, color565(0, 64, 255), rotate=15)sleep(3)display.clear()display.fill_circle(132, 132, 70, color565(0, 255, 0))sleep(1)display.draw_circle(132, 96, 70, color565(0, 0, 255))sleep(1)display.fill_ellipse(96, 96, 30, 16, color565(255, 0, 0))sleep(1)display.draw_ellipse(96, 256, 16, 30, color565(255, 255, 0))sleep(5)display.cleanup()class Demo(object):"""Touchscreen simple demo."""CYAN = color565(0, 255, 255)PURPLE = color565(255, 0, 255)WHITE = color565(255, 255, 255)def __init__(self, display, spi2):"""Initialize box.Args:display (ILI9341): display objectspi2 (SPI): SPI bus"""ledCfg = TLedConfig()self.display = displayself.touch = Touch(spi2, cs=Pin(ledCfg.T_CS), int_pin=Pin(ledCfg.T_IRQ),int_handler=self.touchscreen_press)# Display initial messageself.display.draw_text8x8(self.display.width // 2 - 32,self.display.height - 9,"TOUCH ME",self.WHITE,background=self.PURPLE)# A small 5x5 sprite for the dotself.dot = bytearray(b'\x00\x00\x07\xE0\xF8\x00\x07\xE0\x00\x00\x07\xE0\xF8\x00\xF8\x00\xF8\x00\x07\xE0\xF8\x00\xF8\x00\xF8\x00\xF8\x00\xF8\x00\x07\xE0\xF8\x00\xF8\x00\xF8\x00\x07\xE0\x00\x00\x07\xE0\xF8\x00\x07\xE0\x00\x00')def touchscreen_press(self, x, y):"""Process touchscreen press events."""print('touch once ... ...')# Y needs to be flipped# y = (self.display.height - 1) - y# Display coordinatesself.display.draw_text8x8(self.display.width // 2 - 32,self.display.height - 9,"{0:03d}, {1:03d}".format(x, y),self.CYAN)# Draw dotself.display.draw_sprite(self.dot, x ,y, 5, 5)def TouchTest():"""Test code."""ledCfg = TLedConfig()power = Pin(ledCfg.LED, Pin.OUT)power.value(1)spi1 = SPI(2, baudrate=32000000, sck=Pin(ledCfg.SCK), mosi=Pin(ledCfg.SDI))spi2 = SPI(1, baudrate=1000000, sck=Pin(ledCfg.T_CLK), mosi=Pin(ledCfg.T_DIN))display = Display(spi1, dc=Pin(ledCfg.DC), cs=Pin(ledCfg.CS), rst=Pin(ledCfg.RESET))# display = Display(spi1, dc=Pin(4), cs=Pin(16), rst=Pin(17))# spi2 = SPI(2, baudrate=1000000, sck=Pin(18), mosi=Pin(23), miso=Pin(19))Demo(display, spi2)try:while True:idle()except KeyboardInterrupt:print("\nCtrl-C pressed.  Cleaning up and exiting...")finally:display.cleanup()

main.py

from core.WifiManager import WifiManager
from core.screen.TLedCfg import TLedConfig
from core.screen.test import ScreenTest,TouchTestdef main():print("Welcome to MicroPython!")# wifi = WifiManager()# wifi.start_ap("esp32","12345678")if __name__ == '__main__':main()ScreenTest()# TouchTest()

main函数里,测试哪个就把另一个注释就好。

附录:

  • 驱动和参考主要来自如下:https://github.com/rdagger/micropython-ili9341

  • LVGL:https://github.com/lvgl/lvgl/tree/b66512183ab0ba3b36e8175504fa6fe9cd6e5312

  • ESP32引脚参考大全ESP32 – GPIO 引脚参考大全 – 凌顺实验室 (lingshunlab.com)

相关文章:

【micropython】SPI触摸屏开发

背景&#xff1a;最近买了几块ESP32模块&#xff0c;看了下mircopython支持还不错&#xff0c;所以买了个SPI触摸屏试试水&#xff0c;记录一下使用过程。硬件相关&#xff1a;SPI触摸屏使用2.4寸屏幕&#xff0c;常见淘宝均可买到&#xff0c;驱动为ILI9341&#xff0c;具体参…...

【云原生】k8s中Pod进阶资源限制与探针

一、Pod 进阶 1、资源限制 当定义 Pod 时可以选择性地为每个容器设定所需要的资源数量。 最常见的可设定资源是 CPU 和内存大小&#xff0c;以及其他类型的资源。 当为 Pod 中的容器指定了 request 资源时&#xff0c;调度器就使用该信息来决定将 Pod 调度到哪个节点上。当还…...

AI - stable-diffusion(AI绘画)的搭建与使用

最近 AI 火的一塌糊涂&#xff0c;除了 ChatGPT 以外&#xff0c;AI 绘画领域也有很大的进步&#xff0c;以下几张图片都是 AI 绘制的&#xff0c;你能看出来么&#xff1f; 一、环境搭建 上面的效果图其实是使用了开源的 AI 绘画项目 stable-diffusion 绘制的&#xff0c;这是…...

应用场景五: 西门子PLC通过Modbus协议连接DCS系统

应用描述&#xff1a; 西门子PLC&#xff08;S7200/300/400/200SMART&#xff09;通过桥接器可以支持ModbusRTU串口和ModbusTCP以太网&#xff08;有线和无线WIFI同时支持&#xff09;两种通讯方式连接DCS系统&#xff0c;不需要编程PLC通讯程序&#xff0c;直接在模块中进行地…...

我继续问了ChatGPT关于SAP顾问职业发展前景的问题,大家感受一下

目录 SAP 顾问 跟其他IT工作收入情况相比是怎么样的&#xff1f; 如何成为SAP FICO 优秀的顾问 要想成为SAP FICO 优秀的顾问 &#xff0c;需要ABA开发技能吗 SAP 顾问中哪个类型收入最多&#xff1f; 中国的ERP软件能够取代SAP吗&#xff1f; 今天我继续撩 ChatGPT。随便问…...

Python小白入门---00开篇介绍(简单了解一下)

Python 小白入门 系列教程 第一部分&#xff1a;Python 基础 介绍 Python 编程语言安装 Python 环境变量和数据类型运算符和表达式控制流程语句函数和模块异常处理 第二部分&#xff1a;Python 标准库和常用模块 Python 标准库简介文本处理和正则表达式文件操作和目录操作时…...

【算法基础】C++STL容器

一、Vector 1. 初始化(定义) (1)vector最基本的初始化: vector <int> a;(2)定义长度为10的vector: vector <int> a(10);(3)定义长度为10的vector,并且把所有元素都初始化为-3: vector <int...

【经典蓝牙】蓝牙 A2DP协议分析

A2DP 介绍 A2DP(Advanced Audio Distribution Profile)是蓝牙高音质音频传输协议&#xff0c; 用于传输单声道&#xff0c; 双声道音乐&#xff08;一般在 A2DP 中用于 stereo 双声道&#xff09; &#xff0c; 典型应用为蓝牙耳机。 A2DP旨在通过蓝牙连接传输高质量的立体声音…...

Objective-C 构造方法的定义和声明规范

总目录 iOS开发笔记目录 从一无所知到入门 文章目录源码中 NSArray 的构造方法与命名规律自定义类的构造方法命名截图代码输出源码中 NSArray 的构造方法与命名规律 interface NSArray<ObjectType> (NSArrayCreation) (instancetype)array;(instancetype)arrayWithObject…...

Matlab图像处理学习笔记

Matlab图像处理 Matlab基础 数组 1、向量 生成方式1: x = [值] x = [1 2 3] % 行向量 y = [4; 5; 6] % 列向量 z = x % 行向量转列向量...

笔记(三)——迭代器的基础理论知识

迭代器是一种检查容器内元素并且遍历容器内元素的数据类型。它提供对一个容器中的对象的访问方法&#xff0c;并且定义了容器中对象的范围。一、vector容器的iterator类型vector容器的迭代器属于随机访问迭代器&#xff0c;一次可以移动多个位置。vector<int>::iterator …...

没有公网ip怎么外网访问nas?快解析内网端口映射到公网

对于NAS用户而言&#xff0c;外网访问是永远绕不开的话题。拥有NAS后的第一个问题&#xff0c;就是搞定NAS的外网访问。不过众所周知&#xff0c;并不是所有的小伙伴都能得到公网IP&#xff0c;由于IPV4资源的枯竭&#xff0c;一般不会被分配到公网IP。公网IP在很大程度上除了让…...

spring integration使用:消息转换器

系列文章目录 …TODO spring integration开篇&#xff1a;说明 …TODO spring integration使用&#xff1a;消息路由 spring integration使用&#xff1a;消息转换器 spring integration使用&#xff1a;消息转换器系列文章目录前言消息转换器&#xff08;或者叫翻译器&#x…...

Vue3电商项目实战-商品详情模块7【21-商品详情-评价组件-头部渲染、22-商品详情-评价组件-实现列表】

文章目录21-商品详情-评价组件-头部渲染22-商品详情-评价组件-实现列表21-商品详情-评价组件-头部渲染 目的&#xff1a;根据后台返回的评价信息渲染评价头部内容。 yapi 平台可提供模拟接口&#xff0c;当后台接口未开发完毕或者没有数据的情况下&#xff0c;可以支持前端的开…...

地址,指针,指针变量是什么?他们的区别?符号(*)在不同位置的解释?

指针是C语言中的一个重要概念&#xff0c;也是C语言的一个重要特色&#xff1b;使用指针&#xff0c;可以使程序简洁、紧凑、高效。不掌握指针&#xff0c;就没有掌握C语言的精华。 目录 一、定义 1.1地址 1.2指针 1.3指针变量 1.4指针和指针变量的区别 二、使用指针变量…...

【MongoDB】一、MongoDB的安装与部署

【MongoDB】一、MongoDB的安装与部署实验目的实验内容实验步骤一、下载MongoDB安装包二、创建文件夹data及子文件夹db和log三、启动MongDB服务1. 在命令行窗口执行启动MongoDB服务命令2. 打开mongodb.log3. 打开浏览器进行启动验证四、登录MongoDB五、配置环境变量六、将MongDB…...

《爆肝整理》保姆级系列教程python接口自动化(二十三)--unittest断言——上(详解)

简介 在测试用例中&#xff0c;执行完测试用例后&#xff0c;最后一步是判断测试结果是 pass 还是 fail&#xff0c;自动化测试脚本里面一般把这种生成测试结果的方法称为断言&#xff08;assert&#xff09;。用 unittest 组件测试用例的时候&#xff0c;断言的方法还是很多的…...

MySQL的mvcc

mvcc&#xff08;多版本并发控制&#xff09; MVCC 是通过数据行的多个版本管理来实现数据库的并发控制 。使得在InnoDB的事务隔离级别下执行 一致性读操作有了保证。可以认为是行级锁的变种&#xff0c;在很多情况下可以避免加锁&#xff0c;开销更低 mvcc没有正式的标准&…...

vite:常见的配置

最近在捣鼓一下vite&#xff0c;因为自己一直在使用react&#xff0c;就选择vite、react来体验一下vite。 使用最简单的方法创建一个应用&#xff1a;yarn create vite&#xff0c;然后选择react框架。 vite默认配置是使用了defineConfig工具函数&#xff1a; import { defi…...

计算机图形学:liang算法和Cyrus-Beck算法

其中Cyrus-Beck算法呢&#xff0c;是计算一根直线一个多边形的交线段&#xff1b;liang算法是Cyrus的一个特例&#xff0c;即多边形刚好是矩形&#xff1b;先看看Cyrus算法的思路【从别的博客找的图片】&#xff1a;这很容易理解&#xff0c;点积>0时就可能中内部嘛&#xf…...

React组件之间的通信方式总结(上)

先来几个术语&#xff1a; 官方我的说法对应代码React elementReact元素let element<span>A爆了</span>Component组件class App extends React.Component {}无App为父元素&#xff0c;App1为子元素<App><App1></App1></App> 本文重点&…...

C++17 nodiscard标记符

文章目录前言弃值表达式nodiscard标记符函数非弃值声明类/枚举类/结构 非弃值声明返回类引用与类指针前言 在C 17中引入了一个标记符nodiscard&#xff0c;用于声明一个 “非弃值(no-discard)表达式”。那么在开始之前&#xff0c;我们需要了解一下什么是弃值表达式。 弃值表…...

SAP 寄售业务的标准流程

SAP的标准寄售业务&#xff0c;供应商提供的物料只有在公司使用之后才需支付应付账款&#xff0c;类似是一种先吃后付钱的餐饮流程。 SAP的寄售流程把实际业务中的供应商&#xff0c;采购方收货&#xff0c;采购方消耗物料&#xff0c;采购方依据消耗物料数量进行付款&#xff…...

操作系统高频知识

目录 一、线程与进程的区别 区别&#xff1a; 二、多进程和多线程区别 三、进程与程序的区别 三、死锁 1、是什么 2、产生的原因 3、产生的必要条件&#xff08;4个&#xff09; 4、如何预防 5、如何避免 6、如何检测 7、如何解除 一、线程与进程的区别 1、线程&a…...

加载预训练模型,模型微调,在自己的数据集上快速出效果

针对于某个任务&#xff0c;自己的训练数据不多&#xff0c;先找到一个同类的别人训练好的模型&#xff0c;把别人现成的训练好了的模型拿过来&#xff0c;换成自己的数据&#xff0c;调整一下参数&#xff0c;再训练一遍&#xff0c;这就是微调&#xff08;fine-tune&#xff…...

VScode远程连接服务器-过程试图写入的管道不存在-could not establist connection to【已解决】

问题描述 使用服务器的过程中突然与服务器断连&#xff0c;报错如下&#xff1a;could not establist connection to [20:23:39.487] > ssh: connect to host 10.201.0.131 port 22: Connection timed out > [20:23:39.495] > 过程试图写入的管道不存在。 > [20…...

电子技术——B类输出阶

电子技术——B类输出阶 下图展示了一个B类输出阶的原理图&#xff0c;B类输出阶由两个互补的BJT组成&#xff0c;不同时导通。 原理 当输入电压 vI0v_I 0vI​0 的时候&#xff0c;两个晶体管都截止输出电压为零。当 vIv_IvI​ 上升至超过0.5V的时候&#xff0c;此时 QNQ_NQN…...

【老卫搬砖】034期:HarmonyOS 3.1 Beta 1初体验,我在本地模拟器里面刷短视频

今天啊打开这个DevEco Studio的话&#xff0c;已经提示有3.1Beta1版本的一个更新啊。然后看一下它的一些特性。本文也演示了如何在本地模拟器里面运行HarmonyOS版短视频。 主要特性 新特性包括&#xff1a; Added support for Windows 11 64-bit and macOS 13.x OSs, as well…...

Day901.内部临时表 -MySQL实战

内部临时表 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于内部临时表的内容。 sort buffer、内存临时表和 join buffer。这三个数据结构都是用来存放语句执行过程中的中间数据&#xff0c;以辅助 SQL 语句的执行的。 其中&#xff0c;在排序的时候用到了 sort bu…...

jstatd的启动方式与关闭方式

启动方式与注意事项&#xff1a; 启动方式&#xff1a; 前台启动不打印日志&#xff1a; jstatd -J-Djava.security.policyjstatd.all.policy -J-Djava.rmi.server.hostname服务器IP 前台启动并打印日志&#xff1a; ./jstatd -J-Djava.security.policyjstatd.all.policy -…...

b2c网站建设价格/企业网页制作

AWR中有 DB time这个术语&#xff0c;那么什么是DB time呢&#xff1f; Oracle10gR2 官方文档 给出了详细解释(Oracle10gPerformance Tuning Guide 5.1.1.2 Time Model Statistics) The most important of the time model statistics is DB time. This statistics represents t…...

Wordpress网站转zblog/外贸网站如何推广优化

推荐阅读第一篇博客&#xff1a;https://blog.csdn.net/qq_37534947/article/details/106628308 因为在写第一篇的时候对于kitti数据集的用法总结的不是太清楚&#xff0c;这里根据可视化代码&#xff0c;然后重新总结一下其主要的流程认知&#xff1a; 一&#xff1a;点云数据…...

wordpress安装伪静态/万能浏览器

Aster&#xff08;A*&#xff09;算法 Aster算法是在Dijkstra算法基础上发展出来的&#xff0c;是在静态路径中用于求解最优路径有效的直接搜索算法&#xff0c;比dijkstra算法多了一个启发式的搜索函数&#xff0c;也就是通过一个代价函数来确定搜索方向&#xff08;从起点开…...

给别人做网站赚钱吗/网站优化推广排名

#include <stdio.h> //宏定义接收参数&#xff1a;替换操作&#xff0c;不会预先计算参数,而是直接将参数带入到表达式中进行替换 #define QQ(x, y) x *y //23*3112// 普通函数接收参数&#xff1a;传递的是值&#xff0c;会在传递参数的时候预先计算参数&#xff0c;然后…...

我要找人做网站的主页/手机百度网盘网页版登录入口

目录&#xff08;TOC&#xff09;是Word文档的重要组成部分。它提供了文档内容的概述&#xff0c;并允许您快速导航到所需的部分。您可能会遇到需要以编程方式从Word文档中添加&#xff0c;提取&#xff0c;更新或删除目录的情况。为此&#xff0c;本文将教您如何使用C 处理Wor…...

个人资讯网站建设/上海抖音seo公司

大家好&#xff0c;我是吴星宇&#xff0c;一名在校计算机系大学生&#xff0c;你们可以叫我小吴&#xff0c;今天21.6.19学校已经开始了考试周&#xff0c;而我这学期也完成了c语言的学习。对编程有着足够的兴趣&#xff0c;接下来会陆续发布一些c语言的博客&#xff0c;在学习…...