【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触摸屏开发
背景:最近买了几块ESP32模块,看了下mircopython支持还不错,所以买了个SPI触摸屏试试水,记录一下使用过程。硬件相关:SPI触摸屏使用2.4寸屏幕,常见淘宝均可买到,驱动为ILI9341,具体参…...

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

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

应用场景五: 西门子PLC通过Modbus协议连接DCS系统
应用描述: 西门子PLC(S7200/300/400/200SMART)通过桥接器可以支持ModbusRTU串口和ModbusTCP以太网(有线和无线WIFI同时支持)两种通讯方式连接DCS系统,不需要编程PLC通讯程序,直接在模块中进行地…...

我继续问了ChatGPT关于SAP顾问职业发展前景的问题,大家感受一下
目录 SAP 顾问 跟其他IT工作收入情况相比是怎么样的? 如何成为SAP FICO 优秀的顾问 要想成为SAP FICO 优秀的顾问 ,需要ABA开发技能吗 SAP 顾问中哪个类型收入最多? 中国的ERP软件能够取代SAP吗? 今天我继续撩 ChatGPT。随便问…...
Python小白入门---00开篇介绍(简单了解一下)
Python 小白入门 系列教程 第一部分:Python 基础 介绍 Python 编程语言安装 Python 环境变量和数据类型运算符和表达式控制流程语句函数和模块异常处理 第二部分: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)是蓝牙高音质音频传输协议, 用于传输单声道, 双声道音乐(一般在 A2DP 中用于 stereo 双声道) , 典型应用为蓝牙耳机。 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 % 行向量转列向量...
笔记(三)——迭代器的基础理论知识
迭代器是一种检查容器内元素并且遍历容器内元素的数据类型。它提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围。一、vector容器的iterator类型vector容器的迭代器属于随机访问迭代器,一次可以移动多个位置。vector<int>::iterator …...

没有公网ip怎么外网访问nas?快解析内网端口映射到公网
对于NAS用户而言,外网访问是永远绕不开的话题。拥有NAS后的第一个问题,就是搞定NAS的外网访问。不过众所周知,并不是所有的小伙伴都能得到公网IP,由于IPV4资源的枯竭,一般不会被分配到公网IP。公网IP在很大程度上除了让…...

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

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

地址,指针,指针变量是什么?他们的区别?符号(*)在不同位置的解释?
指针是C语言中的一个重要概念,也是C语言的一个重要特色;使用指针,可以使程序简洁、紧凑、高效。不掌握指针,就没有掌握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断言——上(详解)
简介 在测试用例中,执行完测试用例后,最后一步是判断测试结果是 pass 还是 fail,自动化测试脚本里面一般把这种生成测试结果的方法称为断言(assert)。用 unittest 组件测试用例的时候,断言的方法还是很多的…...
MySQL的mvcc
mvcc(多版本并发控制) MVCC 是通过数据行的多个版本管理来实现数据库的并发控制 。使得在InnoDB的事务隔离级别下执行 一致性读操作有了保证。可以认为是行级锁的变种,在很多情况下可以避免加锁,开销更低 mvcc没有正式的标准&…...

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

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

测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...

基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...

初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...
前端高频面试题2:浏览器/计算机网络
本专栏相关链接 前端高频面试题1:HTML/CSS 前端高频面试题2:浏览器/计算机网络 前端高频面试题3:JavaScript 1.什么是强缓存、协商缓存? 强缓存: 当浏览器请求资源时,首先检查本地缓存是否命中。如果命…...

车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...