ESP32驱动墨水屏实战:GxEPD2库入门与避坑指南
1. 为什么选GxEPD2库来驱动墨水屏1.1 墨水屏和普通屏的驱动逻辑完全不一样刚开始从LCD转到墨水屏的时候我第一反应是这不就是个不怎么刷新的屏吗用以前那套SPI/FSMC驱动方式还不是照样跑结果翻了车。墨水屏的工作原理决定了它不能用逐行扫描的方式持续刷新而是要通过驱动芯片给每一个像素施加特定的电压波形让黑白粒子发生翻转而且翻转完成后不需要持续供电也能保持画面。这意味着控制逻辑里必须有刷新时序、波形查找表、BUSY忙状态等待这些环节。普通屏幕你往显存里写像素就完事了哪怕写慢点只要不断刷新屏幕就正常显示。墨水屏不行你得先告诉驱动IC我现在要开始刷新了IC会走一整段波形有的长达两秒中间你要是又发命令打断它画面直接花掉甚至永久性残影。用ESP32和Arduino环境开发时如果自己从寄存器层面去写这些流程光适配一款屏幕的驱动IC就要折腾好几天。1.2 GxEPD2库到底解决了什么问题GxEPD2库是Jean-Marc Zingg一直在维护的开源库它把所有主流墨水屏驱动IC的初始化序列、刷新波形、命令设置全部封装好了。你不需要去翻SSD1680的寄存器手册也不需要自己去算LUT查找表只需要在代码里指定屏幕型号然后调用几个简单的API就能完成初始化、清屏、显示文字、显示图片。更重要的是GxEPD2不是只支持某一片特定型号它把当前市面上常见的黑白、三色、四灰度墨水屏几乎都收进来了。你换屏幕的时候往往只需要改一个驱动类宏定义代码结构完全不用动。我后来从2.9寸黑白屏换到4.2寸三色屏程序主体部分就改了十几行这比我预想的要省事太多了。1.3 对比U8g2和Adafruit_EPDGxEPD2的优势在哪国内很多Arduino玩家习惯用U8g2因为它在OLED这类屏上确实好用。但U8g2对墨水屏的支持比较有限它走的是像素点阵渲染的思路对墨水屏的部分刷新和全屏刷新模式区分不够细尤其是三色屏和四灰度屏U8g2基本无能为力。Adafruit_EPD库也不错但它更多是围绕Adafruit自家模块设计的换成淘宝上几十块钱的通用墨水屏模组引脚定义和驱动芯片对不上就得自己改库挺遭罪的。GxEPD2走的是一个框架按屏幕选驱动类的路子。你买到的屏幕模块只要驱动芯片在支持列表里就能用同一套初始化流程。遇到不支持的型号也可以继承现有类或者新增一个驱动类社区里已经有不少人这么干过。1.4 支持范围与项目适配参考我目前用过的GxEPD2支持屏幕包括常见的1.54寸、2.13寸、2.9寸、4.2寸、7.5寸驱动芯片涵盖IL3829、SSD1680、SSD1675、UC8151等。颜色分类上有纯黑白、黑白红三色、黑白黄三色、四灰阶刷新方式上有全刷和局刷。做桌面温湿度计、日程提醒牌、电子标签、离屏时钟都比较合适。下面要讲的这个项目就是拿ESP32开发板配2.9寸黑白墨水屏完整走一遍GxEPD2的驱动流程。2. 硬件准备与开发环境搭建2.1 硬件清单与选型建议ESP32开发板我用的是一块ESP32 DevKitC带CH340串口芯片的那种Arduino IDE识别为ESP32 Dev Module2.9寸黑白墨水屏模块驱动IC是SSD1680常见于微雪、合宙等模块杜邦线若干最好选母对母方便把屏幕模块直接插到ESP32开发板上面包板和3.3V稳压模块如果手头屏幕模块是5V逻辑供电版本建议先看规格书这里有个提醒很多墨水屏模块自带电平转换电路可以直接用3.3V供电和逻辑但有些便宜的模块是裸屏转接板逻辑电平可能是5V。ESP32的GPIO最高输出3.3V如果要驱动5V逻辑的模块建议加一块电平转换板否则可能出现画面乱码或者DC/CS引脚拉不低的情况。2.2 Arduino IDE里配置ESP32核心我用的是Arduino IDE 2.x开发板管理器里加ESP32支持。打开文件-首选项-附加开发板管理器网址填入官方那个JSON地址然后在开发板管理器里搜索ESP32安装最新版。这个流程很多教程都有但我想重点说一句务必装稳定版或者较新的release版本实测有些老版本会导致GxEPD2在编译时报一些莫名其妙的SPI头文件错误。装好之后在开发板菜单里选ESP32 Dev ModuleFlash Size选4MB其余默认就行。2.3 安装GxEPD2库打开库管理器搜索GxEPD2认准作者Jean-Marc Zingg点击安装。同时建议顺手装一下Adafruit GFX库虽然GxEPD2不强制依赖它但显示文字时要用的字体文件就是从Adafruit GFX里带的装好能省一堆编译报错。GxEPD2库安装后会自带大量示例其中有一个文件夹叫examples/GxEPD2_Example里面用宏定义的方式列出了几十种屏幕型号新手可以直接在头文件里把对应的宏打开。2.4 引脚规划原则别让墨水屏占了串口和下载引脚ESP32的引脚很多但并不是每个都能随便接。第一个要注意的坑是GPIO34到GPIO39只能做输入不能做输出所以CS、DC、RST、BUSY绝对不能接到这几个脚上。第二个坑是GPIO0、GPIO2、GPIO15这些影响启动模式的引脚虽然能作为普通输出用但接线稍长就可能影响下载和启动。为了避免麻烦我一般把墨水屏的四个控制脚放到GPIO4、GPIO5、GPIO16、GPIO17这些干净的引脚上。SPI的MOSI和SCK则用ESP32默认的VSPI引脚也就是GPIO23和GPIO18。MISO一般用不到墨水屏是单工通信但有些模块有BUSY反馈已经用独立GPIO处理了。3. 引脚配置详解与接线实战3.1 墨水屏模块引脚定义市面上常见的2.9寸墨水屏模块接口引脚基本是这几个引脚名作用VCC电源正极一般接3.3VGND电源地DIN / MOSISPI数据输入CLK / SCKSPI时钟CS片选信号低电平有效DC数据/命令切换RST复位信号低电平有效BUSY忙状态输出高电平表示忙有些模块还会多一个PWR_CTRL或排针带NC不用管。屏幕模块上如果丝印写的是DIN、CLK那就对应ESP32的MOSI和SCK别傻乎乎找MISO。3.2 推荐接线表ESP32 DevKitC我的接线方案如下墨水屏引脚ESP32引脚VCC3V3GNDGNDDIN23 (MOSI)CLK18 (SCK)CS5DC17RST16BUSY4这个组合的好处是避开了下载时可能被占用的串口引脚和启动配置引脚同时和Arduino-ESP32的默认SPI定义完全一致代码里不用额外设置SPI引脚。如果你的开发板引脚丝印不方便可以把CS/DC/RST/BUSY换到其他输出引脚但代码里的构造函数参数必须同步换。3.3 代码中初始化GxEPD2对象打开Arduino IDE新建一个工程先把这段代码贴进去#include GxEPD2_BW.h #include Fonts/FreeMonoBold9pt7b.h #include Fonts/FreeSans9pt7b.h #define EPD_CS 5 #define EPD_DC 17 #define EPD_RST 16 #define EPD_BUSY 4 GxEPD2_BWGxEPD2_290_T94_V2, GxEPD2_290_T94_V2::HEIGHT display( GxEPD2_290_T94_V2(/*CS*/ EPD_CS, /*DC*/ EPD_DC, /*RST*/ EPD_RST, /*BUSY*/ EPD_BUSY) ); void setup() { Serial.begin(115200); display.init(115200); } void loop() { }注意GxEPD2_BW的模板参数第一个是屏幕驱动类第二个是屏幕的HEIGHT这个值在对应的驱动类里已经定义好了直接写GxEPD2_290_T94_V2::HEIGHT就行。对象构造时把四个控制引脚按顺序填进去接线不对或者对象参数写错后续的显示肯定出问题。如果手头屏幕和我不一样比如是1.54寸的就去GxEPD2库自带的GxEPD2_Example里把你那块屏幕对应的宏定义复制过来把对象声明替换掉。不同屏幕的构造参数个数是一样的只是驱动类名不同。3.4 供电和电平注意事项墨水屏刷新瞬间的电流比待机时要高不少有些模块峰值能到20-30mA虽然ESP32开发板的3.3V稳压器一般能顶住但如果同时接了其他外设比如温湿度传感器、OLED、蜂鸣器建议用外部3.3V稳压模块统一供电否则可能出现在屏幕刷新瞬间ESP32自动重启的情况。另外千万不要把5V接进VCC想当然供电更稳定很多墨水屏模块的VCC走的是逻辑电平转换芯片接了5V会把后级芯片烧掉。先看模块丝印如果写了3.3V-5V兼容再考虑5V。4. 基础显示文本与图形4.1 初始化流程里的几个关键细节display.init()不仅是初始化驱动IC它还会调用reset复位屏幕所以执行init之前要确保CS/DC/RST/BUSY已经接好。init之后我习惯立刻调用display.setRotation(1)把屏幕旋转到横屏状态不然默认竖屏在2.9寸屏上看起来特别窄后面排版麻烦。display.firstPage()和display.nextPage()是GxEPD2特有的分页刷新机制看起来有点像状态机。每次都把要显示的东西全部画在缓冲区里然后nextPage()会真正把缓冲区推给屏幕驱动。以2.9寸为例屏幕分辨率是128x296全屏刷新如果不开分页ESP32的P SRAM可能不够用。这个分页机制对新手来说很抽象只要记得一个套路display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.setCursor(...); display.print(...); // 画其他东西 } while (display.nextPage());do-while会一直分页刷新直到整屏画完千万不要在中间加delay或者长时间阻塞操作。4.2 显示文本字体、坐标与对齐GxEPD2通过Adafruit GFX的字体来绘制文字。默认不带任何字体时display.print()只会画一个字符占位框必须手动设置字体。比如display.setFont(FreeMonoBold9pt7b); display.setTextColor(GxEPD_BLACK); display.setCursor(10, 30); display.print(Hello ESP32);这里的坐标是字符左上角的基础线位置跟普通LCD的写法一样。但墨水屏不像LCD那样有个普遍用的图形库GxEPD2的文字没有自动居中函数实际排版时得自己计算。比如要在宽度为128像素的屏幕上居中绘制TEMP: 25C先算一下字符像素宽度2.9寸的9pt字体差不多一个字符6像素自己手写一个居中算法最可靠。字体文件在Fonts/目录下常用的有FreeMonoBold9pt7b、FreeSans9pt7b、FreeSansBold12pt7b。文件名称里的数字是pt字号7b表示7位编码。如果显示中文自带的字体不支持需要用u8g2_font工具转中文字库或者自己用图片方式显示中文这一点后面会提到。我一般项目里的中文标题都是用图片处理。4.3 绘制图形矩形、圆、线墨水屏最实用的图形API就是fillScreen、drawRect、fillRect、drawCircle、drawLine。做一个简单的信息卡片时可以这样画边框display.drawRect(5, 5, display.width() - 10, display.height() - 10, GxEPD_BLACK); display.fillRect(20, 40, 50, 30, GxEPD_BLACK);这里有个细节display.width()和display.height()在setRotation之后会变化比如横屏后width是296height是128所以动态获取尺寸比写死数字更稳妥。画完图形后如果你不想整块区域全刷成黑色又想做一个反色效果可以手动对指定区域做像素遍历异或但GxEPD2_BW类本身没有提供xOr操作简单项目用填充矩形就够了。4.4 一个小例子做一个横向时间卡片我把这些基础API组合起来做了一个开机显示时间日期的小卡片完整代码如下void displayDateTime(const char* timeText, const char* dateText) { display.setRotation(1); display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.setFont(FreeSansBold12pt7b); display.setTextColor(GxEPD_BLACK); display.setCursor(20, 35); display.print(timeText); display.setFont(FreeMonoBold9pt7b); display.setCursor(20, 60); display.print(dateText); display.drawRect(10, 10, display.width() - 20, display.height() - 20, GxEPD_BLACK); } while (display.nextPage()); }实际测试下来从调用到显示完大概要2到3秒屏幕会先闪一下然后慢慢出图。这是正常的全屏刷新过程GxEPD2默认用慢速刷新能有效减少残影。如果你想加快速度GxEPD2里有些屏幕驱动类支持display.epd2.setPaged之类的参数调整但提高刷新速度会增加残影风险后面会细说。5. 图像显示从数组到本地图片5.1 图像显示前必须搞清楚的三个约束墨水屏显示图片不像手机屏幕那么自由首先分辨率要匹配2.9寸屏是128x296你拿一张1920x1080的图直接塞进去肯定不行必须压缩到目标分辨率。其次是颜色深度黑白墨水屏只能显示两种颜色彩图需要经过二值化处理。最后是存储格式GxEPD2的drawBitmap接口接收的是const unsigned char*数组每个bit对应一个像素要么把图片转成这种数组直接编译进固件要么从SD卡读取BMP文件在运行时解析。5.2 用取模工具生成C数组我最常用的方式是电脑端先用Python的Pillow库处理图片再输出C数组。也可以用Image2LCD这类工具但实测Image2LCD默认输出格式需要手工调整还是Python可控。例程代码from PIL import Image img Image.open(input.png).convert(1).resize((128, 296)) pixels img.load() out [] for y in range(0, 296, 8): for x in range(128): byte 0 for bit in range(8): if y bit 296 and pixels[x, y bit] 127: byte | (1 bit) out.append(byte) with open(image.h, w) as f: f.write(const unsigned char logo[] {\n) for i in range(0, len(out), 12): f.write( , .join(f0x{val:02X} for val in out[i:i12]) ,\n) f.write(};\n)生成的头文件里是一个unsigned char数组在Arduino工程里#include image.h然后用这几行显示extern const unsigned char logo[]; display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.drawBitmap(20, 10, logo, 128, 296, GxEPD_BLACK); } while (display.nextPage());注意drawBitmap的宽度和高度参数必须和数组里存的分辨率保持一致而且这里的GxEPD_BLACK指的是前景色如果数组第1位表示黑色那传GxEPD_BLACK就是正常显示。这个方向搞反了图片会变成负片效果。5.3 从SD卡读取BMP显示的方案如果你希望机器跑起来后随时换图不想每次重新编译烧录可以把BMP文件放在SD卡里。SD卡和墨水屏同时挂在SPI总线上需要给SD卡单独一个CS引脚比如GPIO21。代码里要用到SD_MMC或SD库。这个方案的好处是图片文件可以直接用USB拷到SD卡里内容更新非常方便。具体流程是初始化SPI把SD库和GxEPD2都指向同一个SPI对象。然后读取BMP文件头部确认文件确实是24位或32位BMP格式再逐像素解析成单bit缓存。GxEPD2库中也提供drawBitmap参考代码在examples/GxEPD2_Example里有一个从SD卡读取BMP的函数但完整度不够需要自己补全解析函数。这里贴一个精简版的读取24位BMP并显示的核心概念void drawBMPFromSD(const char* filename) { File bmpFile SD.open(filename); if (!bmpFile) return; uint8_t header[54]; bmpFile.read(header, 54); int width header[18] | (header[19] 8) | (header[20] 16) | (header[21] 24); int height header[22] | (header[23] 8) | (header[24] 16) | (header[25] 24); int bitCount header[28] | (header[29] 8); // 这里省略BMP行对齐和像素读取细节 // 最终把每个像素二值化后写入GxEPD2的缓冲 }BMP的行数据是倒序存储的而且每行要按4字节对齐新手很容易在这两个地方踩坑。如果不是必须用SD卡建议先用C数组方式等基础显示跑通了再升级到SD卡。5.4 灰度与抖动处理2.9寸SSD1680这种屏本身只支持1bit黑白但有些4灰阶的墨水屏比如UC8151GxEPD2对应的是GxEPD2_4G类可以显示4种灰度。如果只有黑白屏又想显示灰度照片可以用Floyd-Steinberg抖动算法把灰度图转成黑白点阵图视觉上会有类似报纸照片的网点效果。Python里Pillow库自带抖动转换img Image.open(gray.jpg).convert(L).resize((128, 296)) img img.convert(1, ditherImage.FLOYDSTEINBERG)然后按照前面pickle方式转成数组。抖动算法会让画面边缘更自然不会出现大面积色块但屏幕刷新时间会明显增加。实测一张经过抖动的图片全刷时间能从2秒涨到3秒多。6. 实测踩坑与问题排查6.1 白屏先别怀疑库查供电和时序白屏是墨水屏驱动最典型的故障我遇到三次白屏两次是供电问题一次是复位时序问题。第一次屏幕模块的VCC接了ESP32的5V模块上的稳压芯片当场发热但没烧画面始终全白。换回3.3V后正常。第二次是杜邦线CS引脚接触不良屏幕初始化白屏后来把CS线换成焊接线解决。第三次更隐蔽BUSY引脚一直悬空没有接到ESP32GxEPD2在初始化时等不到ICU空闲标志直接超时返回屏幕当然白屏。如果你确认接线没问题可以在display.init()前面手动加一个复位时序pinMode(EPD_RST, OUTPUT); digitalWrite(EPD_RST, LOW); delay(20); digitalWrite(EPD_RST, HIGH); delay(200);有些屏幕的复位电路比较敏感GxEPD2内部虽然会发复位命令但自己手动拉低再拉高能让驱动IC状态更可预测。还有一点BUSY引脚必须接并且代码里构造GxEPD2对象时传入的BUSY引脚要跟实际一致GxEPD2在大部分刷新场景下会等待BUSY变低接错或者悬空就是白屏或刷新卡死。6.2 花屏和残影刷新模式与温度的影响花屏常见于在屏幕刷新过程中又调用了display.hibernate()或者在上一次刷新还没结束时再次调用display.nextPage()。墨水屏刷新需要完整走完波形中断刷新会产生乱七八糟的灰阶残留。GxEPD2里对刷新保护还算严格正常情况下不会并行刷新但如果你在loop里频繁调用刷新函数要自己加一个布尔标志位避免冲突。残影是墨水屏的天性全屏刷新时GxEPD2会执行一整轮先清全黑再清全白再出图的流程残影会轻很多。如果你用局部刷新模式比如只改一个数字那残影就挺明显。低温环境下残影会更重温度低于10度时最好先做一次全屏预热刷新否则画面会灰蒙蒙一片。6.3 GxEPD2爷爷级问题驱动类选错与内存溢出评论区经常会看到有人说我的屏幕也是2.9寸为什么代码编译不过大概率是驱动类选错了。同样是2.9寸墨水屏微雪的V1版本和V2版本驱动芯片不一样可能是SSD1680和SSD1681或者旧版是IL3829选错驱动类不是编译报错就是初始化乱码。建议看一眼屏幕背面芯片丝印然后去GxEPD2的README或者GxEPD2_display_selection.h里找对应型号。ESP32虽然有240KB左右的RAM但GxEPD2在分页模式下也需要预留大概8KB到32KB的缓冲区。Arduino IDE的默认堆设置一般够用但如果你在代码里用了大量String拼接或者开过大的全局数组可能刷屏时触发重启。我习惯用ESP.getFreeHeap()打印一下空闲堆内存至少保留30KB以上再刷新。6.4 常见问题速查表现象可能原因处理方案全白屏VCC供电错误、CS虚接、BUSY悬空检查供电电压重新插拔/焊接CSBUSY接GPIO4初始化卡死RST时序不对、驱动类选错手动复位确认屏幕芯片型号画面花屏刷新中途被中断、时钟频率过高降低SPI速度到4MHz刷新期间禁止其他中断残影严重没走全屏刷新流程、低温强制全屏清黑再全清白预热后再出图编译报错模板参数不对、缺少Adafruit GFX检查GxEPD2_BW模板参数安装Adafruit GFX显示负片效果前景色设置反了检查drawBitmap最后一个参数屏幕闪烁但无内容DC引脚接错或驱动类不匹配确认DC引脚换成对应驱动类7. 进阶思路与低功耗优化7.1 用Deep Sleep把待机电流降到微安级墨水屏最大的价值就是静态显示不耗电所以低功耗是这个领域绕不开的话题。很多ESP32开发板自带的USB转串口芯片在睡眠时也会耗电几毫安所以我后来做低功耗项目时直接把板子上的稳压器和串口芯片跳线断开只用电池供ESP32芯片。代码侧使用esp_deep_sleep_start()定时唤醒后刷新一次数据然后继续睡。GxEPD2的display.hibernate()进入休眠时屏幕功耗几乎为零但注意hibernate之后不能直接重新显示需要先调用display.init()重新初始化或者直接调用display.wakeup()。我的低温湿度计大概每30分钟唤醒一次读取传感器、刷新屏幕、再睡4节18650电池并联可以跑大半年。如果你也想做类似项目唤醒后建议先读RTC内存判断这次唤醒是不是无效唤醒避免因为GPIO touch wake触发导致频繁刷新。7.2 局部刷新和功耗的平衡墨水屏局部刷新可以显著降低刷新功耗因为不需要把整个屏幕的粒子都翻转一遍。GxEPD2的display.writeImage()接口可以指定区域或者是使用display.firstPage()配合display.setPartialWindow()。但局部刷新的残影问题比全刷严重尤其是大块黑色区域更新时。我自己的策略是重要信息比如日期、标题采用全刷数字变化部分采用局刷并且每天固定一个时间全刷一次清残影。这样既省电又不会出现越用越糊的情况。7.3 扩展多块屏幕、传感器和远程更新如果你以后想玩更复杂的可以用ESP32的一路SPI接多块墨水屏每一块用独立CS片选。刷新的时候先选中对应屏幕再调用GxEPD2对象的显示函数。GxEPD2也支持建立多个display实例但要注意同一时刻只能有一个实例在总线上工作。配合传感器比如DHT11或BME280把温湿度、空气质量画成卡片就是完整的桌面信息屏。再往后可以加WiFi拉取天气API或者用WebServer做一个小后台上传图片到SD卡更新屏幕这个项目就能演变成一个自用的电子公告牌了。最后分享一个我自己的小习惯每次给墨水屏写布局前先在纸上把坐标算一遍尤其注意setRotation之后宽高是否变化。我因为在横屏和竖屏之间反复切换经常出现字和边框错位后来干脆强制把屏幕固定为一个方向所有尺寸取display.width()和display.height()动态计算。这样哪怕换屏代码也不用改坐标。做墨水屏项目最大的乐趣就在排错和打磨布局的过程希望这篇梳理能让你少走点弯路。

相关新闻

Claude Code 从 npm 迁移到原生安装后,Anthropic marketplace 安装失败重试的排查与配置骨架

Claude Code 从 npm 迁移到原生安装后,Anthropic marketplace 安装失败重试的排查与配置骨架

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 3:40:55 阅读更多 →
Buildah 依赖剖析:modern-go/concurrent 的并发 Map 与可取消 Goroutine Executor

Buildah 依赖剖析:modern-go/concurrent 的并发 Map 与可取消 Goroutine Executor

云原生 【免费下载链接】buildah A tool that facilitates building OCI images. 项目地址: https://gitcode.com/gh_mirrors/bu/buildah 点击查看 免费下载 本文以 Buildah 仓库中 vendor 目录下的 modern-go/concurrent 库文档为主体,完整讲解该库提供…

2026/9/25 3:40:54 阅读更多 →
AI Agent工程落地指南:从模型调用到结果交付

AI Agent工程落地指南:从模型调用到结果交付

做了两年多AI Agent项目,带过团队也踩过无数坑,我最大的感受是:AI Agent工程师真正要解决的,不是"调用模型",而是"交付结果"。这个区别几乎决定了一个Agent项目是停留在Demo阶段,还是能…

2026/9/25 3:40:54 阅读更多 →

最新新闻

低功耗电压检测电路:MOS管开关控制电阻分压,将待机电流降至nA级

低功耗电压检测电路:MOS管开关控制电阻分压,将待机电流降至nA级

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 4:59:53 阅读更多 →
Arduino IDE安装ESP8266卡在99%?换源与离线包方案彻底解决

Arduino IDE安装ESP8266卡在99%?换源与离线包方案彻底解决

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 4:59:53 阅读更多 →
Flowbite 搜索输入框组件完全指南:从基础搜索栏到语音搜索与高级筛选

Flowbite 搜索输入框组件完全指南:从基础搜索栏到语音搜索与高级筛选

UI组件前端 【免费下载链接】flowbite Open-source UI component library and front-end development framework based on Tailwind CSS 项目地址: https://gitcode.com/gh_mirrors/fl/flowbite 点击查看 免费下载 搜索框是每个站点的“入口级”交互组件。本篇基于…

2026/9/25 4:59:53 阅读更多 →
ESP32-C3 当管家:软件模拟 SWD 实现 RP2040 固件下载与日志采集

ESP32-C3 当管家:软件模拟 SWD 实现 RP2040 固件下载与日志采集

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 4:59:53 阅读更多 →
产线烧录良率排查全攻略:从硬件连接到固件格式的链路诊断

产线烧录良率排查全攻略:从硬件连接到固件格式的链路诊断

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 4:59:53 阅读更多 →
从 Codex CLI 到知识库:TaoToken 统一 Key 驱动的 AI 代理个人知识管理全流程

从 Codex CLI 到知识库:TaoToken 统一 Key 驱动的 AI 代理个人知识管理全流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 4:58:52 阅读更多 →

日新闻

AI元人文:从工具使用到思维重构的深度探索

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:00:41 阅读更多 →
Python+CNN车牌识别实战:从数据预处理到模型训练与部署

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:00:41 阅读更多 →
Vim基础操作全攻略:保存退出、模式切换与高频命令实战

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/25 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →