ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

用HLK-806/801驱动ST7789:16位并口方案提速与避坑指南

用HLK-806/801驱动ST7789:16位并口方案提速与避坑指南 简介面向HLK-806与HLK801开发板的ST7789 16位并行接口LCD驱动资源包专供嵌入式开发者解决160×128像素TFT彩屏的并口驱动与底层适配问题适合需要快速点亮屏幕并学习并口通信的入门至中级开发者。压缩包共4个文件含2个C源码与2个头文件整体仅3KB代码精简易读。st7789_parallel_16.c/h实现并行接口初始化、命令发送、数据写入、寄存器设置等核心函数lcd.c/lcd.h提供显示方向切换、清屏、颜色模式等上层操作并针对HLK-806与HLK801完成GPIO引脚映射。资源重点展示了16位并口的数据同步与时序控制方式包括数据有效时钟、读写时钟、使能信号等关键环节。通过阅读和实际调试可熟悉ST7789驱动框架掌握并口读写时序参数配置并能据此移植到其他微控制器平台。目前已有1497人学习下载适合嵌入式显示项目开发和硬件调试场景参考。1. 用 HLK-806/801 驱动 ST7789为什么偏偏要开 16 位并口手头有块 HLK-806 或 HLK-801想让它直接驱动一块 ST7789 的 240×320 屏。按大多数教程走 4 线 SPI简单界面还能看一旦刷中文菜单、动态曲线或整屏地图刷新时间立刻拖到几十毫秒肉眼可见地卡。换成 ST7789 的 16 位并口也就是 8080 时序之后数据线每次写 16 位RGB565 一个像素刚好一笔写完同样频率下带宽比 SPI 高出一截。这个方案解决的是刷屏带宽和延迟问题适合做仪表盘、中文菜单、需要整屏重绘的小型人机界面。下面直接从协议拆起把 GPIO 模拟并口、初始化序列、DMA 优化和踩坑一起说清楚。2. 16 位并口的 8080 协议拆开看WR、RS、D0~D15 怎么接2.1 8080 写时序到底在干什么ST7789 的并口不是并行总线那种带地址线的接口它更像一个“用控制线驱动的数据管道”。真正参与写的控制线只有四条CS片选、RS也叫 D/CX区分命令和数据、WR写使能、RST复位。数据线 D0~D15 在 16 位模式下一次承载一个完整的 16 位值RD 线在只写显示时不接也行但调试时最好留个测试点。写一个命令的流程是CS 拉低RS 拉低表示“接下来是命令”把命令字节放到 D0~D7 上16 位模式下高 8 位被忽略然后把 WR 拉低再拉高形成一个上升沿ST7789 在 WR 上升沿采样数据。写数据则完全一样只是 RS 要拉高。整个动作里没有时钟线WR 就是节拍器所以 GPIO 模拟并口的核心是“把 WR 翻转得又快又干净”。需要注意 16 位模式下的一个隐藏细节写命令时虽然总线是 16 位但命令本身通常只有 8 位真正有效的是低 8 位数据线写参数时如果参数是 8 位同样放到低 8 位高 8 位置 0。很多人第一次从 SPI 迁移到并口习惯把两个 8 位参数拼成一个 16 位值一次写完这会让 ST7789 把两个参数当成一个参数处理画面就会出现毫无规律的错位。时序参数上ST7789 的数据手册给出的 WR 最小脉冲宽度大约在 15ns 量级GPIO 模拟时很难压到这个值所以一般不需要刻意追求极限速度。我通常把目标定在 50~100ns 的周期上这样既稳定又能保证整屏刷新在可接受范围内。如果连 100ns 都跑不到问题多半出在代码层面比如用库函数一位一位翻 IO或者每次写数据前都做引脚状态检查。2.2 HLK-806/801 的引脚分配两组 GPIO 凑出 16 位数据线HLK-806/801 这类模组的 GPIO 数量不像桌面级 MCU 那么阔绰但要把 16 根数据线拆到两个 8 位端口上还是能做到的。最常见的接法是把 D0~D7 接到 GPIOA 的低 8 位D8~D15 接到 GPIOB 的低 8 位控制线单独用 PC4~PC7。这样安排的好处是写 16 位数据时只需要分别操作 GPIOA-ODR 和 GPIOB-ODR 的低字节不需要额外的位运算去拼接不连续的引脚。信号引脚信号引脚D0PA0D8PB0D1PA1D9PB1D2PA2D10PB2D3PA3D11PB3D4PA4D12PB4D5PA5D13PB5D6PA6D14PB6D7PA7D15PB7CSPC4RSPC5WRPC6RSTPC7如果你的板子把某几个引脚复用到了调试串口或 LED 上那就得提前在系统初始化里把这些复用关掉。还有一个容易被忽略的问题HLK-806/801 的部分引脚可能同时连接了板载外设上电后默认状态会和 LCD 数据线打架。我一般会在初始化函数的最开头把 D0~D15 全配置成推挽输出并拉到低电平再拉一次复位避免屏幕出现鬼影。如果 GPIO 数量实在不够常见做法是在模块和屏幕之间加一片 74LVC245 做数据缓冲用 8 位并口加一个锁存信号来模拟 16 位或者干脆放弃直接驱动把 HLK 当数据源、外部 MCU 当显示控制器。标题既然写“适用于”说明这套驱动最关心的还是让这两颗模组直接做事所以我后面的代码都按“两组 8 位 GPIO 拼 16 位”来写。2.3 硬件裁剪不是所有引脚都要接电平也要较真很多 ST7789 模组是 40Pin 排线引出的板上已经用 IM 引脚把接口模式固定成了 16 位并口所以不用再管 IM[3:0] 怎么接。真正需要自己决定的硬件问题有三个RD 接不接、背光怎么控、电平怎么转换。RD 在纯写显示时可以不接。ST7789 只有读显存、读 ID 时才需要 RD 拉低配合 RS 拉高而这些操作在驱动跑起来之后几乎用不到。不过我在调试初期会临时飞一根线出来因为回读 ID 能确认模组是不是真的工作在并口模式、线序有没有接错。确认完再拆掉省得长时间占用一个 GPIO。背光控制线通常叫 BLK 或 LEDA不要直接接 3.3V 电源最好串一个限流电阻或者接到一个独立的 PWM 引脚上。背光 LED 的正向导通压降和电流需求跟屏幕批次有关直接满电怼上去轻则亮度异常重则烧背光。HLK-806/801 的引脚大多不是 5V 耐受而 ST7789 的逻辑电平也是 3.3V所以两者之间一般不需要电平转换芯片。唯一要注意的是如果屏的供电是 5V 方案有些模组板载了 5V 转 3.3V 的 LDO那逻辑信号仍然要以屏的 3.3V 域为准别把 5V 直接串进 RS/WR。这张引脚表其实就是最小系统接线原理图不需要额外的地址译码、锁存器或读总线。做好这层基础后面跑驱动的时候才能把问题缩小到“代码”和“时序”两个变量上。3. 最小驱动代码在 HLK-806/801 上用 GPIO 模拟并口跑通画点3.1 引脚定义与底层写函数直接操作 ODR别用库函数先看最底层的引脚宏定义。我习惯把控制线宏和两个数据端口分开写这样换板子时只需要改一处。#define LCD_CS_PORT GPIOC #define LCD_CS_PIN GPIO_PIN_4 #define LCD_RS_PORT GPIOC #define LCD_RS_PIN GPIO_PIN_5 #define LCD_WR_PORT GPIOC #define LCD_WR_PIN GPIO_PIN_6 #define LCD_RST_PORT GPIOC #define LCD_RST_PIN GPIO_PIN_7 #define LCD_DATA_A_PORT GPIOA // D0~D7 #define LCD_DATA_B_PORT GPIOB // D8~D15在写数据之前先把 GPIO 初始化做好。所有数据线要配置成推挽输出、速度拉到最高档。控制线也是推挽输出但 RST 可以先保持输出低电平。这里有个容易翻车的点如果 HLK 跑的是 RTOS 或者裸机加中断写数据函数执行期间不能被任务切换打断否则 D0~D15 可能写到一半被中断服务函数改掉屏幕出现随机的花点。底层写 16 位数据的函数有讲究。用库函数一位一位写是最慢的做法整屏填充时性能会掉一个数量级。正确做法是直接写 ODR 寄存器同时把两个端口的低 8 位数据一次性更新掉static inline void lcd_write_data16(uint16_t dat) { // D0~D7 在 GPIOA 低 8 位D8~D15 在 GPIOB 低 8 位 GPIOA-ODR (GPIOA-ODR 0xFF00) | (dat 0x00FF); GPIOB-ODR (GPIOB-ODR 0xFF00) | ((dat 8) 0x00FF); // WR 脉冲先拉低再拉高数据在上升沿被锁存 LCD_WR_PORT-BSRR LCD_WR_PIN; // 拉低 LCD_WR_PORT-BSRR LCD_WR_PIN 16;// 拉高 }这段代码的关键点有两个。第一端口低 8 位之外的位必须保留原值因为那个端口可能还有其他外设引脚直接赋值会误伤。第二WR 脉冲用 BSRR 寄存器产生BSRR 写 1 拉低、写高 16 位拉高比先读 ODR 再改 ODR 快也天然避免了“读-改-写”的竞态。命令和数据共用这个底层函数只是 RS 电平不同static inline void lcd_write_cmd(uint8_t cmd) { LCD_CS_PORT-BSRR LCD_CS_PIN; // CS 拉低 LCD_RS_PORT-BSRR LCD_RS_PIN; // RS0命令模式 lcd_write_data16((uint16_t)cmd); // 高 8 位无效 LCD_CS_PORT-BSRR LCD_CS_PIN 16; // CS 拉高 }这里要注意命令本身只有 8 位强制转成 16 位后高 8 位是 0正好符合 ST7789 对 16 位并口写命令的定义。如果你把命令和高 8 位掩码一起处理反而容易出错。3.2 初始化序列一组不用每条都懂的常用命令集ST7789 的初始化序列在不同模组之间大同小异但有一条铁律上电后要等屏幕内部稳定再退出睡眠不能一上来就写显存。下面的函数是裸机环境下的典型流程static void st7789_init(void) { // 硬件复位RST 拉低至少 10us再拉高 LCD_RST_PORT-BSRR LCD_RST_PIN; delay_us(20); LCD_RST_PORT-BSRR LCD_RST_PIN 16; delay_ms(120); // 等待内部电压稳定 lcd_write_cmd(0x11); // SLPOUT退出睡眠 delay_ms(120); // 必须等足时间 lcd_write_cmd(0x36); // MADCTL扫描方向与 RGB/BGR 顺序 lcd_write_data16(0x00); lcd_write_cmd(0x3A); // COLMOD像素格式 lcd_write_data16(0x55); // 16 位 RGB565 lcd_write_cmd(0x20); // INVON反色关闭 lcd_write_cmd(0x29); // DISPON开显示 }这段序列看起来简单但每个命令背后都有讲究。0x36 的 MADCTL 控制扫描方向、行列互换以及颜色顺序0x00 表示正屏、RGB 顺序如果你的模组是 BGR 排列画面颜色就会红蓝对调这时需要把 0x36 的参数改成 0x08 或在原方向值上加 8。0x3A 写成 0x55 表示 16 位色ST7789 支持 0x528 位、0x5312 位、0x5516 位、0x6618 位等格式很多并口花屏问题就出在这里——模组出厂配置可能是 18 位而驱动代码按 16 位写显存。延时不能省尤其是退出睡眠后的 120ms。ST7789 内部 DC/DC 转换器和显示电压的建立需要时间如果在这之前写显存轻则白屏重则整屏雪花点。还有一点初始化失败后不要立刻重试至少断电等 1 秒再重新上电否则电容上的残压会让复位时序无效。3.3 画点与填充函数窗口指令是并口驱动的分水岭画点函数是所有显示代码的地基但它的实现方式直接影响性能。ST7789 允许我们先设置一个矩形窗口再连续写像素数据写完自动回到窗口起点如果只做单点绘制那每一次都要重新设置窗口static void lcd_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { lcd_write_cmd(0x2A); // 列地址 lcd_write_data16(x0 8); lcd_write_data16(x0 0xFF); lcd_write_data16(x1 8); lcd_write_data16(x1 0xFF); lcd_write_cmd(0x2B); // 行地址 lcd_write_data16(y0 8); lcd_write_data16(y0 0xFF); lcd_write_data16(y1 8); lcd_write_data16(y1 0xFF); lcd_write_cmd(0x2C); // 开始写显存 }注意这里每个地址参数虽然只有 8 位但必须分两次调用 lcd_write_data16不能合成一个 16 位值一次写出去。0x2A 和 0x2B 的地址都是 15 位有效所以高字节和低字节要分开。窗口是闭区间x0、x1、y0、y1 都要包含在内。有了窗口函数画单点和整屏填充就变得很直接static void lcd_draw_pixel(uint16_t x, uint16_t y, uint16_t color) { lcd_set_window(x, y, x, y); lcd_write_data16(color); } static void lcd_fill_rect(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color) { lcd_set_window(x0, y0, x1, y1); for (uint32_t i 0; i (uint32_t)(x1 - x0 1) * (y1 - y0 1); i) { lcd_write_data16(color); } }画单点每次都走 0x2A/0x2B/0x2C 三个命令效率很低所以 UI 层应该尽量避免逐点绘制。整屏填充 240×320 像素时循环次数是 76800 次如果每次 lcd_write_data16 里多做一条判断、一个延时总耗时就会差出好几倍。我通常会把“连续写 n 个相同颜色值”单独封装一层方便后面用 DMA 优化时替换。4. 三个必做的优化DMA 搬运、窗口连续写、局部刷新4.1 让 DMA 把帧缓冲搬进 ODR刷新率提升的关键步骤GPIO 模拟并口的极限瓶颈在 WR 脉冲频率但真正让刷新率上不去的往往是每写一个像素都要 CPU 去执行“更新 ODR、拉低 WR、拉高 WR”这个过程。如果代码里再带循环计数和函数调用开销跑满 16 位并口的性能优势就成了一句空话。最常见的优化手段是三件事直接操作寄存器、关中断、用 DMA 批量搬运。如果 HLK-806/801 的内部 MCU 带有 DMA 控制器那可以把帧缓冲定义为一个 uint16_t 数组然后让 DMA 在内存和外设寄存器之间做搬运。这里的“外设”不是 SPI 外设而是 GPIO 的 ODR 寄存器。以 STM32 的 HAL 为例DMA 配置的关键参数是这样一组hdma_tim.Init.Direction DMA_MEMORY_TO_PERIPH; // 帧缓冲 - ODR hdma_tim.Init.PeriphInc DMA_PINC_DISABLE; // 外设地址固定 hdma_tim.Init.MemInc DMA_MINC_ENABLE; // 内存地址递增 hdma_tim.Init.PeriphDataAlignment DMA_PDATAALIGN_HALFWORD; hdma_tim.Init.MemDataAlignment DMA_MDATAALIGN_HALFWORD; hdma_tim.Init.Mode DMA_CIRCULAR; // 循环搬运外设地址填 GPIOA-ODR 或 GPIOB-ODR注意前面引脚分配里 D0~D15 分在两组端口那么单个 DMA 通道只能搬运一半数据。有两条路一是把数据线的两组端口放到同一个 16 位端口上需要硬件支持二是用两个 DMA 通道分别搬运高 8 位和低 8 位但这要求帧缓冲也拆成两个字节数组比较别扭。所以我更推荐的做法是如果没有一个连续的 16 位 GPIO 端口就别强行 DMA退回到高效的 ODR 手动翻转仍然比 SPI 快。WR 信号的同步也是 DMA 方案里最容易被忽略的环节。DMA 只是把数据放到 GPIO 引脚上并不负责产生 WR 脉冲。常见做法是把 WR 引脚复用为定时器通道让定时器以固定频率输出 PWM同时触发 DMA 搬运数据线和 WR 各自独立看起来像是数据“提前”或“延后”到达但只要数据在 WR 上升沿之前稳定就没有问题。这个方案对时序要求较高我建议先用逻辑分析仪抓一次波形确认建立时间再写死参数。4.2 整屏重绘不要反复 SetWindow一次窗口写到底窗口连续写是性价比最高的优化不需要任何硬件特性纯粹靠代码习惯就能提升一倍的刷新速度。很多初版的驱动在画矩形、画图片、画背景时每个像素都调用一次 lcd_set_window这等于每画一个点都要把 0x2A/0x2B/0x2C 三个命令各写一遍命令开销比像素数据本身上升一个量级。正确做法是把“设置窗口”和“写像素块”分开。UI 层在渲染一个控件时先计算出它覆盖的矩形区域调用一次 lcd_set_window然后循环写像素数据。ST7789 的地址指针在窗口内是自动递增的写完一行的最后一个像素会自动跳到下一行开头不需要软件去干预。这也意味着你的绘制函数必须严格按照“从左到右、从上到下”的顺序输出像素如果中间跳过了某些位置画面就会错位。有一个细节0x2C 命令发出后后续所有写数据操作都会被当作像素数据直到重新发命令为止。所以如果你在 set_window 之后还想写命令必须先把 CS 拉高再拉低或者显式发一个 NOP 命令否则 ST7789 还在等像素数据接到命令字节会把它当颜色值塞进显存。这个现象在调试时非常迷惑整屏都是奇怪的竖条纹但代码看起来逻辑完全正确。4.3 局部刷新与脏矩形让 UI 动起来而不是整屏闪16 位并口的带宽再高也不建议每次按键、每次数值变化都整屏重绘。仪表盘上可能只是温度值变了两位数整屏 240×320 全刷一遍不仅浪费带宽还会带来肉眼可见的闪烁。我一般会在 UI 层维护一个脏矩形区域把需要变化的最小矩形范围合并起来。比如一个温度数字控件高度 24 像素、宽度 64 像素刷新它时只需要 set_window 到这个区域再把数字的字模像素写进去。如果有多个控件同时变化就计算它们的包围盒一次窗口写完。这样做的性价比很高因为 ST7789 的窗口机制天然支持任意矩形不需要额外开销。背光控制也要配合这个节奏。如果整屏秒杀重绘一次背光 PWM屏幕会像呼吸灯一样忽明忽暗正确做法是只在页面切换或长时间无操作时调整背光动态内容刷新期间保持背光恒定。HLK-806/801 如果有硬件 PWM 引脚背光频率建议放在 1kHz 以上太低会听到电感啸叫。4.4 双缓冲与撕裂感什么时候才需要它如果你的界面有摄像头预览、高速波形滚动这类频繁整屏更新的需求局部刷新就不够用了得考虑双缓冲。一个帧缓冲用于后台绘制另一个用于 DMA 发送绘制完成后交换指针。这样做会把“绘制”和“发送”重叠起来能显著提高帧率但代价是内存占用翻倍——240×320×2 字节约 150KB对 HLK-806/801 这类模组可能比较紧张。有一个折中方案只在水平方向上做撕裂保护。ST7789 支持 Tearing Effect 信号线能输出当前扫描位置配合 DMA 可以做到只在整个刷新循环开始时切入新帧避免画面上下半截不一致。这不算双缓冲但能在内存有限的情况下减轻撕裂感。实践上我一般先确认 HLK 有多少空闲 RAM再决定要不要开双缓冲如果内存不够宁可帧率低一点也别让系统在刷新时崩溃。5. 避坑笔记花屏、白屏、写数据太快翻车的三个典型症状5.1 画面颜色发紫、红蓝对调现象整屏填充红色屏幕上显示的是蓝色或紫色显示白色时又正常但彩色图片看起来像调色板错了。原因0x3A 像素格式被设成了 18 位模式驱动却按 16 位 RGB565 写入或者 MADCTL 里的 BGR 位和模组实际的 RGB 排列不匹配。ST7789 的 0x3A 参数如果被模组初始化代码改成了 0x66那么并口每个写周期实际只取了 18 位中的一部分颜色分量错位就会出现紫边。解决每次初始化时都显式写 0x3A 参数为 0x55并且把 0x36 的 bit3 清零。如果换了一个批次屏幕之后颜色仍然反就把 0x36 参数在 0x00 和 0x08 之间切换测试画面中红色和蓝色互换就说明是这里错了。5.2 初始化后纯白屏写任何像素都没有反应现象代码执行完初始化屏幕全白但背光正常用手触摸屏幕有时能看到微弱残影。原因最普遍的是复位和退出睡眠的顺序错了。ST7789 要求 RST 拉低至少 10us拉高后要等内部供电稳定然后发 0x11 退出睡眠还要再等 120ms。很多人沿用 SPI 屏的初始化代码省掉了第二次长延时结果屏幕收到了显存写入命令但内部驱动电路还没准备好。解决按上一章给的延时参数放宽RST 拉低 20ms退出睡眠后等 150ms。如果仍然白屏检查 RS 线是否和 WR 线接反——两个引脚在排线上经常是相邻的飞线时容易交叉。5.3 整屏刷新速度反而比 SPI 还慢现象初始化正常画面正常但整屏填充 240×320 花了 600ms 以上比原来的 SPI 驱动还慢。原因底层写数据函数用了库函数逐引脚翻转或者在每个写周期里插了延时。并口的优势要在“一个写周期完成 16 位数据传输”的前提下才成立如果一次写数据要执行十几条 GPIO 库函数调用那它的速度优势会被函数调用开销抵消。解决用寄存器直接赋值替代库函数关中断后测量一次 WR 高低电平翻转的耗时。如果单次写周期在 1us 左右说明每次调用里有多余的检查或延时优化目标是让单次写周期压缩到 200ns 以内。用逻辑分析仪或者示波器夹在 WR 线上看连续脉冲的间隔是最直接的验证手段。5.4 窗口内出现规律的斜纹或整行错位现象显示字符或图片时内容不是整体偏移而是每隔几行就出现一条肉眼可见的错位线。原因0x2A/0x2B 的地址参数高位和低位顺序写反或者窗口设置时把 x0、x1 的上下限写反。ST7789 的列和行地址都是 15 位有效必须先写高位再写低位一旦两边顺序不一致写入的像素会以一个偏移折叠到窗口里形成斜纹。解决先用纯色整屏填充排除数据线错误再画一个单色边框并比较四个边的位置就能判断是列方向还是行方向偏移。把 lcd_set_window 里的参数顺序统一成“先高后低”的循环不要复制粘贴后改错变量名。6. 进阶让 ST7789 显示中文字库与 16 位 RGB565 的一次配合6.1 中文字库的两个方案内置字库不存在离线点阵才靠谱很多刚接触 ST7789 的人会问屏幕能不能直接显示中文有没有中文字库。ST7789 本身只是一颗显示驱动芯片内部没有中文字库所以中文显示要么靠外部字库芯片要么靠程序里内置字模。对 HLK-806/801 这类资源有限的模组我建议直接用离线点阵字模。16×16 点阵的一个汉字在普通点阵格式下只有 32 字节如果先渲染成 16 位 RGB565 的图片再存储一个字要 512 字节字体一多内存立刻爆掉。6.2 把点阵字模展开成 RGB565颜色前景和背景分开处理显示一个汉字的过程本质上就是把点阵数据里的每 1 bit 翻译成前景色或背景色。正常字模每行两个字节高位在前逐位判断后写入对应像素void lcd_draw_char(uint16_t x, uint16_t y, const uint8_t *bitmap, uint16_t fg_color, uint16_t bg_color) { uint8_t byte_h, byte_l; for (uint8_t row 0; row 16; row) { byte_h bitmap[row * 2]; // 高 8 位 byte_l bitmap[row * 2 1]; // 低 8 位 for (uint8_t col 0; col 8; col) { uint16_t color (byte_h (0x80 col)) ? fg_color : bg_color; lcd_write_data16(color); } for (uint8_t col 0; col 8; col) { uint16_t color (byte_l (0x80 col)) ? fg_color : bg_color; lcd_write_data16(color); } } }注意这里每个点都调用一次 lcd_write_data16效率不高。实际工程里我会先扫描一行 16 像素把相同颜色的连续段合并成几个“色块”矩形再做窗口写入这样能减少写周期数量。如果你在 MicroPython 环境里复刻这套逻辑定义颜色数组时一定要用 16 位整数类型常见写法是from array import array后array(H, [fg_color])否则整数溢出会把 RGB565 的高字节丢掉。6.3 验证帧耗时与字库正确性先量再优化验证优化成果时别用眼睛看我用一个简单的计数器记录一次整屏填充前后的系统 tick然后打印出来。整屏 76800 个像素如果耗时超过 50ms说明并口时序还有优化空间如果字库显示出现缺笔画优先检查字模数据的行字节顺序是按“逐行 2 字节”存储还是“逐列”存储不同取模软件的输出格式完全不一样。遇到这种情况我一般会先用纯色背景和单色边框把屏幕的显示方向调正再谈字模适配——希望帮到你。本文还有配套的精品资源点击获取
返回列表