恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

SH1107驱动的1.5寸OLED屏在STM32上的移植与调试

  • 首页
  • 资讯中心
  • /
  • SH1107驱动的1.5寸OLED屏在STM32上的移植与调试

相关资讯

PyQt5+YOLOv5+SQLite垃圾分类系统(本地离线可运行) 2026/10/21 7:58:27
C#与S7-200 SMART以太网通讯实战:从选型到代码 2026/10/21 7:58:27
给 AI 的文档先统一成 Markdown:PDF、Word、Excel、图片转换实操指南 2026/10/21 7:58:27

最新资讯

Playwright动态网页爬虫实战:滚动加载与点击翻页的通用处理套路
图表设计实战指南:从架构图到流程图的高效信息表达
服务停了端口还没放出来:TIME-WAIT 与端口复用
artcraft创意流水线:从想法到成品的工程化实践
Stanley算法详解:自动驾驶横向控制的几何方法实战
artcraft:模板+参数+渲染三层架构实现批量创意图片生成

今日推荐

SAP 屏幕上的金额未必存在数据库表里,从 WB2R_SV 的 Net Amount 看懂运行时计算
具身智能中‘指哪打哪’的视觉语言动作联合建模
AI时代人工翻译技术博客的价值与实践指南

本周热门

基于GMM的语音识别系统原理与MATLAB实现详解
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

SH1107驱动的1.5寸OLED屏在STM32上的移植与调试

发布时间:2026/10/21 8:03:28
SH1107驱动的1.5寸OLED屏在STM32上的移植与调试 搞这玩意儿之前我先说个挺关键的判断X150-2828KSWKG01-H25这个屏物料清单上写的可能是“LCD液晶显示模组”但驱动芯片是SH1107说明它本质是一片OLED点阵屏只是行业里习惯把这类小尺寸显示模组继续叫“LCD”或“LCM”。型号里的X150基本可以猜是1.5英寸2828大概率是指玻璃外形尺寸28mm×28mm这两个特征合起来正好对应SH1107驱动芯片最常见的应用场景128×128分辨率的OLED面板。后面驱动代码里那些坑比如列地址范围、显存页数、初始化序列全是围绕这几点展开的。如果你手里是64行版本也就是128×64的条屏代码只需要改两个宏和一行初始化参数其余不用动。我这次是在一个桌面小气象站项目里点亮的这块屏主控用的STM32F1系列开发环境就是常见的MDK全部代码用C写。文章里会把驱动怎么分层、初始化序列为什么这么定、SH1107和SSD1306到底差在哪、刷新和绘图怎么实现、还有我实际调试时踩过的白屏和花屏坑都讲清楚。适合正在做STM32OLED小屏项目、被某个稀有型号屏幕卡住的开发者参考。1. 项目背景为什么是这块屏为什么是SH11071.1 型号解读与选型逻辑X150-2828KSWKG01-H25这个编号拆开看其实挺有意思。X150对应1.5英寸对角线2828是28mm乘28mm的外形尺寸KSWKG应该是模组厂商的产品系列代号H25是设计版本。这种编号规律在小尺寸显示模组里很常见拿到规格书之前先按这个思路猜一遍基本不会差太远。选这块屏的初衷很简单项目需要一个低功耗、接口省引脚、又能做异形显示的屏幕。1.5英寸128×128的OLED分辨率对于显示温湿度曲线、时钟表盘、电量图标来说非常够用。对比同价位的TFT彩屏OLED的优势是自发光、对比度高、不需要背光板静态显示时整屏功耗能控制在很低水平。对比128×64的SSD1306屏最大的区别在于纵向分辨率翻倍刷新一个8×8的汉字时不用再跨页拼接显示小字号字符的笔画细节也更完整。选型时的另一个考量是接口。SH1107支持I2C和SPI两种通信方式对STM32F1这种引脚数量紧张的芯片非常友好。我在项目里一共分配了4个GPIO给屏幕SPI四线模式如果改用I2C直接压缩到2个剩下引脚全部让给传感器和外设板子布局会松很多。但I2C的吞吐量上限摆在那里后面再讲性能优化的时候我会详细算这笔账。1.2 SH1107与SSD1306的本质差异很多新手在驱动这块屏时犯的第一个错误就是直接把SSD1306的开源驱动代码复制过来改改初始化命令结果发现显示区域错位、画面偏移、甚至完全白屏。这两个芯片虽然都是OLED列驱动但内部显存结构不一样。对比项SSD1306SH1107显存容量128×64位132×132位页数量8页0xB0-0xB7最多16页0xB0-0xBF列地址范围0-1270-131内存寻址模式命令支持0x20不支持固定页模式常用分辨率128×64128×128 / 128×64命令兼容性开源资料极多与SH1106接近资料较少最大的坑在第一行SSD1306的显存是128列SH1107的显存是132列。你往数据寄存器写一列数据内部指针是放在0到131这个区间里的。如果设计的是128列显示窗口就必须通过列地址命令把起始列设定在正确位置否则你写进去的第0列数据物理上可能落在带有偏移的SEG引脚上表现出来就是整个画面水平挪了2到4个像素。另一个不太容易注意到的是页地址范围。SSD1306的0xB0到0xB7一共8页SH1107的0xB0到0xBF一共16页。如果你的屏是128×128初始化中显示行数MUX ratio设为128行这时候RAM里实际用到的就是16页如果是128×64的版本只访问前8页即可但页地址命令仍然支持0xB8和0xB9以上的值一旦刷新循环写过头数据会跑到不该显示的行上造成画面上半部分正常、下半部分出现随机噪声。再就是内存寻址模式。SSD1306的0x20命令可以设置页寻址、水平寻址、垂直寻址三种模式SH1107直接就把这个命令砍掉了只能用最原始的页模式先选页再选列然后逐字节写数据。这意味着你在写驱动时不需要考虑水平自动换行这种特性反而让代码更简单了每次刷新重新设置页和列即可。2. 硬件接口设计I2C和SPI怎么选怎么接2.1 接口选型省引脚还是省时间SH1107的I2C接口非常简单两根线就能工作地址一般是0x3C或0x3D。实测在400kHz的I2C时钟下全屏刷新128×128需要大概40毫秒对静态仪表盘完全够用但如果你要做图形动画或者快速翻页肉眼能感觉到明显的刷屏过程。SPI四线模式需要CS、DC、SCK、MOSI四根线加一根可选的RESET。SPI时钟跑到几MHz没有任何压力全屏刷新时间能压到10毫秒以内而且STM32的SPI外设配合DMA能实现后台自动发送CPU占用率极低。实际项目中我把显示刷新放在两处一处在页面加载时全量刷新另一处是每分钟刷新一次温湿度数值区域。用的是SPIDMA方案主循环几乎感觉不到显示的存在。如果你的板子引脚非常紧张或者刷新频率很低I2C足够用如果你有动画交互需求建议直接上SPI。2.2 引脚配置与连接表下面是我在项目里用的SPI引脚分配这里以某STM32F1系列48Pin封装为例逻辑和接线方式对F4、G0同样适用屏幕引脚STM32引脚说明VDD3.3V模块电源注意电流余量VSSGND共地CSPB12SPI片选软件控制DCPB13数据/命令选择高数据低命令SCKPB13(?) 或者直接接SPI1_SCK建议使用硬件SPI对应引脚MOSIPB15SPI主出从入这里要单独提醒一下DC引脚的选择。DC的电平状态必须在SCK上升沿之前稳定下来否则屏幕可能把数据字节误判成命令字节。我的做法是在SPI开始传输之前先写DC引脚再拉低CS顺序不能反。如果用了高速SPIDC引脚建议另外用GPIO控制不要和SPI的MOSI复用否则异步切换会引入毛刺。2.3 电源与复位的细节模块的VDD直接接3.3V内部电荷泵由0xAD/0x8A命令开启后自动升压不需要外部负压电源。这个设计对PCB布局很友好板子上不用放电荷泵电容和负压走线。但要注意一点SH1107的电荷泵开启后VDD引脚电流会有一个瞬间冲击如果板子电源走线太长可能导致电压跌落表现就是屏幕第一帧亮度偏暗或闪烁最直接的办法是在VDD和GND之间放一个4.7μF到10μF的钽电容或MLCC靠近屏幕模组放置。复位引脚的处理也值得说。模组上一般有RESET接到MCU的普通GPIO用软件拉低10毫秒再释放。如果把RESET悬空部分批次的模组上电默认状态不可靠初始化序列可能执行失败这类白屏问题非常隐蔽。稳妥做法是给RESET留一个100nF电容到GND上电时形成硬件延时复位同时GPIO再软件复位一次双重保险。还有一个很常见但容易被忽略的问题是电平匹配。STM32F1的GPIO是3.3V如果系统里同时存在5V器件比如5V供电的传感器或者下载器OLED模组的逻辑引脚绝不能直连5V轻则显示异常重则损坏驱动芯片。检查一下I2C上拉电阻是否接错了电源轨很多开发板的I2C上拉直接拉到5V这个必须改成3.3V。3. 驱动代码框架命令层、缓冲层、绘图层分离3.1 代码目录结构与分层思路驱动代码我没有写成一个巨型文件而是拆成四个模块硬件抽象层负责实际的GPIO和SPI/I2C字节收发命令层负责封装写命令和写数据操作显示缓冲层维护一块和屏幕像素对应的RAM副本绘图层在缓冲区上画点、线、字符最后统一刷新。这样做的好处是换屏或者换主控时只需要改硬件抽象层绘图代码和缓冲管理完全复用。oled/ ├── oled_hw_i2c.c // I2C硬件抽象 ├── oled_hw_spi.c // SPI硬件抽象 ├── sh1107.c // 初始化、刷新、地址管理 ├── sh1107_font.c // 字模数据 ├── sh1107_gfx.c // 画点、线、圆、矩形、字符 └── sh1107.h // 对外接口3.2 硬件抽象层函数指针与多接口支持因为项目后期可能需要在I2C和SPI之间切换验证我在接口层用结构体保存函数指针这样上层代码完全不用变。定义一个操作集typedef struct { void (*init)(void); void (*write_cmd)(uint8_t cmd); void (*write_data)(uint8_t data); void (*write_data_buf)(uint8_t *buf, uint16_t len); } oled_hal_t;这样sh1107.c只调用hal-write_cmd底层是I2C还是SPI完全不影响上层。SPI模式下的write_cmd实现如下注意DC引脚必须在片选之前设置void sh1107_spi_write_cmd(uint8_t cmd) { GPIO_WriteBit(OLED_DC_PORT, OLED_DC_PIN, Bit_RESET); // DC0 GPIO_WriteBit(OLED_CS_PORT, OLED_CS_PIN, Bit_RESET); spi_write_byte(cmd); GPIO_WriteBit(OLED_CS_PORT, OLED_CS_PIN, Bit_SET); } void sh1107_spi_write_data(uint8_t data) { GPIO_WriteBit(OLED_DC_PORT, OLED_DC_PIN, Bit_SET); // DC1 GPIO_WriteBit(OLED_CS_PORT, OLED_CS_PIN, Bit_RESET); spi_write_byte(data); GPIO_WriteBit(OLED_CS_PORT, OLED_CS_PIN, Bit_SET); }如果是I2C写命令和写数据的区别在控制字节命令字节用0x00数据字节用0x40其余过程一样。有些资料里会把控制字节和后续数据放在同一次I2C事务中也可以拆分但要注意部分模组对连续I2C事务的间隔有要求拆太碎会导致时钟延时不达标。我习惯把控制字节和最多16字节数据打包在同一个事务里既保证正确性又减少总线切换开销。3.3 显示缓冲区纵向8位一页的位图布局SH1107的物理显存模型是横向列地址、纵向每8行组成一页。所以缓冲区的排列方式也按这个模型来定义#define OLED_COLS 128 #define OLED_PAGES_64 8 #define OLED_PAGES_128 16 uint8_t g_fb[8][128]; // 64行版本每个字节纵向表示8个像素g_fb[page][col]中page代表纵向第几组8行col代表水平第几列。第0字节的最低位对应屏幕第0行第1位对应第1行依次类推。这个布局和SSD1306完全一致所以如果你以前写过SSD1306的驱动缓冲区的数据结构可以原封不动搬过来。为什么要做一块完整显存缓冲而不是直接把数据推给屏幕因为OLED写入是单向的你没法读回当前屏幕内容做任何局部擦除或叠加都必须依赖本地副本。有了缓冲画图形时先改RAM数组最后一次性把需要的区域推送到屏幕。这也是避免闪烁和局部更新错乱的关键。4. 初始化序列132列显存和128列显示窗口的博弈4.1 一套实测可用的128×128初始化序列初始化序列直接决定了显示是否正常。下面这段是我实测可用的注意里面的注释说明每个参数的物理含义static void sh1107_init(void) { hal-init(); hal-write_cmd(0xAE); // 关闭显示初始化期间必须关屏 hal-write_cmd(0xD5); hal-write_cmd(0x80); // 显示时钟分频比 hal-write_cmd(0x81); hal-write_cmd(0x7F); // 对比度 0x7F可调亮暗 hal-write_cmd(0xA0); // 列地址0映射SEG0若镜像则用0xA1 hal-write_cmd(0xC0); // COM输出方向若上下颠倒则用0xC8 hal-write_cmd(0xA8); hal-write_cmd(0x7F); // 显示行数1/128 hal-write_cmd(0xAD); hal-write_cmd(0x8A); // 开启内部电荷泵 hal-write_cmd(0xD9); hal-write_cmd(0x22); // 预充电周期 hal-write_cmd(0xDB); hal-write_cmd(0x35); // VCOMH电平 hal-write_cmd(0xA6); // 正常显示0xA7为反色 hal-write_cmd(0xAF); // 打开显示 }这段序列里有两个地方最容易出问题。第一是电荷泵如果这条命令丢失或者参数写错屏幕会完全不亮因为内部负压没有建立起来。第二是A8后面的0x7F这个值对应128行显示如果你的屏实际只有64行要改成0x3F否则刷新时下半个屏幕的页数据会写到不存在的行上表现成闪烁或花纹。关于0xA0和0xC0这两个方向命令不同批次模组可能出厂装配方向有差异我在两个不同厂家的128×128模组上踩过完全相反的镜像。建议你先按上面的值点亮如果发现文字/图形左右镜像就把0xA0改成0xA1如果上下颠倒就把0xC0改成0xC8。4.2 列地址设置为什么你的画面会偏移SH1107的RAM有132列我们实际只用了前128列。初始化后列指针默认从0开始这在多数屏上是正确的。但如果你发现整个画面水平偏移了2到4列比如左侧出现窄条空白、右侧被裁掉多半是模组装配时把显示窗口的中心对准了131列RAM的中间位置。这个偏移没法用0xA1这种重映射命令完全解决正确做法是在每次设置列地址时人为加一个偏移量。我的代码里留了一个宏#define OLED_COL_OFFSET 0 // 有些模组需要设成2、4等设置列地址的函数写成这样static void sh1107_set_col(uint8_t col) { col OLED_COL_OFFSET; hal-write_cmd(0x10 | ((col 4) 0x0F)); // 高4位列地址 hal-write_cmd(0x00 | (col 0x0F)); // 低4位列地址 }排查方法是用取模软件生成一个纯竖条纹图案让左侧边缘落在第0列观察条纹交界处和屏幕物理左边框之间的距离偏差就是OFFSET的值。这个方法非常快比反复试命令有效率得多。4.3 页地址设置与全屏刷新的正确姿势页地址命令是0xB0到0xBFSH1107的16个页对应128行每页8行。刷新一页时列地址从设定值开始每写一列数据自动加1直到写满132列或重新设置列地址。这里有个隐蔽的工程问题很多人刷新一屏写128字节就完事但RAM里有132列写128列后列指针停在128如果下一帧忘了重新设置列地址数据会从第128列继续写画面直接错位。所以我在每次刷新页循环的开头都强制调用sh1107_set_col(0)绝不依赖上一次的指针位置。全屏刷新代码void sh1107_refresh_full(void) { for (uint8_t page 0; page OLED_PAGES_64; page) { hal-write_cmd(0xB0 | page); // 选择页 sh1107_set_col(0); // 列指针复位 hal-write_data_buf(g_fb[page][0], OLED_COLS); } }5. 绘图层实现画点、线、字符与局部刷新5.1 画点函数把直角坐标映射到页缓冲前面说过缓冲区是横向列、纵向页的结构。从直角坐标(x,y)映射到缓冲区就是void fb_draw_pixel(int16_t x, int16_t y, uint8_t color) { if (x 0 || x OLED_COLS || y 0 || y 64) return; uint8_t page y 3; // y / 8 uint8_t bit y 0x07; // y % 8 if (color) g_fb[page][x] | (1 bit); else g_fb[page][x] ~(1 bit); }这个函数是后面所有图形的基础性能要求很高。虽然每次画一个点都要做除法和取模但现代编译器对移位运算会做优化实际开销很小。更重要的是这个函数每次调用都判断边界防止画线越界把数组写穿我曾经因为漏了边界判断导致屏幕最右侧出现不可控的随机条纹。5.2 直线、矩形与圆一点点基础算法直线用Bresenham算法这个算法没有浮点运算在MCU上非常合适void fb_draw_line(int16_t x0, int16_t y0, int16_t x1, int16_t y1) { int16_t dx abs(x1 - x0), sx x0 x1 ? 1 : -1; int16_t dy -abs(y1 - y0), sy y0 y1 ? 1 : -1; int16_t err dx dy, e2; while (1) { fb_draw_pixel(x0, y0, 1); if (x0 x1 y0 y1) break; e2 2 * err; if (e2 dy) { err dy; x0 sx; } if (e2 dx) { err dx; y0 sy; } } }矩形、填充矩形这些相对简单本质就是对每条水平线调用画线函数。圆用中点圆算法效率同样很高。图形函数画到缓冲后再统一刷新这是一个非常重要的流程约定绝不让图形函数直接写屏幕硬件所有的几何运算都在内存中完成只有刷新函数才碰硬件。这样设计后动画逻辑根本不用关心屏幕上正在跑什么刷新时直接按区域推最新显存即可。5.3 字符显示8×16 ASCII字模与16×16中文ASCII字符我用的8×16点阵一行16字节横向8位纵向16位一帧一个字符正好对应一页到两页存储。显示字符时从字模表取出16个字节按列写进缓冲区void fb_draw_char(int16_t x, int16_t y, char ch) { const uint8_t *glyph font8x16[ch - 0x20]; for (int i 0; i 16; i) { uint8_t line glyph[i]; for (int bit 0; bit 8; bit) { if (line (1 bit)) fb_draw_pixel(x i, y bit, 1); } } }这个实现直观但速度慢因为每个像素都要单独调用一次画点函数。如果要做文本密集显示推荐的优化是对9个垂直bit做一个字节映射预计算或者直接把字模按页组织用memcpy写入缓冲。16×16中文同理取模时选“16×16、逐行式、低位在前”生成数组后配合GB2312编码查表。取模软件的选择上我常用PCtoLCD2002和Img2Lcd这类离线工具设置好“阴码、逐行、列行式”后生成的C数组可以直接复制进工程。如果是大量中文字符最好用字库工具生成一个按GB2312排序的bin文件运行时用fread按偏移量读取而不是把整个字库塞进程式否则Flash占用会很夸张。5.4 局部刷新只更新变化区域性能提升明显对于时钟或温湿度这种界面全屏刷新是浪费的。每分钟只有几个数字区域变化其余内容完全不变。我实现了矩形区域刷新void sh1107_refresh_rect(uint8_t page_start, uint8_t page_end, uint8_t col_start, uint8_t col_end) { for (uint8_t page page_start; page page_end; page) { hal-write_cmd(0xB0 | page); sh1107_set_col(col_start); for (uint8_t col col_start; col col_end; col) { hal-write_data(g_fb[page][col]); } } }调用时只需要传入变化区域的页范围和列范围。比如温度数值从0到100的被测区域位于第3页到第5页、第20列到第60列刷新的数据量就从全屏的1024字节降到了41×3字节配合DMA几乎是瞬发。这里要提醒局部刷新不会自动清除上一次的内容所以刷新前需要先在自己维护的缓冲区里清掉旧区域再画新内容。6. 调试实录白屏、花屏、乱码的排查流程6.1 白屏先按顺序自查六个方向白屏问题是最让人抓狂的因为看起来像“完全没供电”。我梳理了一个排查顺序按可能性从高到低排列电源3.3V是否送到模组地线是不是虚连。示波器探针量一下VDD。复位RESET引脚有没有保持低电平上电时序对不对。电荷泵确认初始化里有没有0xAD 0x8A这条命令丢了就是白屏。对比度0x81后面的值如果设成0x00显示亮度为零看起来像白屏。初始化顺序0xAE关屏状态如果一直没被0xAF解除驱动芯片不会点亮。I2C地址地址设错时发送的命令全部没人接收模组不会有任何反应。第六个问题在多块屏共用一条总线的系统里尤其隐蔽。我遇到过因为总线上另外一个设备占用相同地址导致通信失败的情况排查方法是在初始化前先发一条0xAE读取ACK能收到ACK说明地址通再往后初始化。6.2 花屏、显示乱码时序和中断是两大元凶花屏多半发生在刷新过程中很典型的场景是DMA刷新到一半定时器中断触发中断服务函数里又改了显存缓冲导致这一帧数据前后不一致屏幕出现撕裂式的花屏。解决办法有两种一种是常规做法绘图和刷新不要并行刷新完一帧再允许改缓冲另一种是高负载做法用双缓冲DMA正在发送缓冲A时所有绘图操作只在缓冲B执行发送完成后再交换角色。我在项目里用了双缓冲开销是两个8×128的RAM数组非常便宜。乱码还有一个常见来源SPI模式下DC引脚时序不对。用逻辑分析仪抓信号时能看到如果DC电平和SCK的跳变沿靠得太近屏幕会把数据字节当成命令字节表现就是同一个字符显示出完全不一样的图案。排查时用示波器看DC和SCK的相对位置确保DC至少提前半个时钟周期稳定。6.3 亮度低或不均匀对比度之外还有两个寄存器亮度问题我一开始只盯着0x81对比度寄存器调整后整屏变亮但边缘总是比中心暗一点。后来发现要同时调三个寄存器才能均匀对比度0x81管总亮度预充电周期0xD9管像素电容的充电时间VCOMH 0xDB管像素驱动电压的最终值。三个参数互相影响调节时观察整个屏幕不要只看中心区域。如果只有局部区域暗淡优先怀疑屏的排线接触尤其是手机排线式的连接器插紧后再测一遍。如果是SPI速率过高导致的数据错误亮度不均匀通常伴随有规律的闪烁降低SPI时钟分频即可。6.4 硬件I2C卡死恢复STM32F1系列的硬件I2C存在一个经典问题总线上出现异常时序后外设会被卡在BUSY状态而且通过普通复位不一定能恢复。我在调试早期吃过这个亏最后处理方式是软件复位外设再配置GPIO外加一个总线恢复例程把SCL拉低后连续发出9个时钟脉冲让总线上任何假状态的外设都释放SDA。void i2c_bus_recover(void) { for (int i 0; i 9; i) { GPIO_WriteBit(SCL_PORT, SCL_PIN, Bit_SET); delay_us(5); GPIO_WriteBit(SCL_PORT, SCL_PIN, Bit_RESET); delay_us(5); } GPIO_WriteBit(SDA_PORT, SDA_PIN, Bit_SET); }如果项目上并不追求硬件I2C效率直接用软件模拟I2C是一个更稳的选择代码改用GPIO翻转实现时序任何引脚都可以接屏幕还能省去总线状态机的调试成本。7. 性能优化与扩展方向7.1 SPIDMA实现零CPU刷屏刷新全屏需要写入8页乘128列共1024字节如果用阻塞式SPI发送CPU在刷新期间要一直等待。改成DMA后发送操作完全交给外设CPU可以继续执行其他任务。关键代码是在SPI发送前把DC和CS设置好然后启动DMA传输在DMA完成中断里拉高CS。void sh1107_refresh_page_dma(uint8_t page) { hal-write_cmd(0xB0 | page); sh1107_set_col(0); GPIO_WriteBit(OLED_DC_PORT, OLED_DC_PIN, Bit_SET); GPIO_WriteBit(OLED_CS_PORT, OLED_CS_PIN, Bit_RESET); SPI_DMACmd(SPI1, SPI_DMAReq_Tx, ENABLE); DMA_Cmd(DMA1_Channel3, ENABLE); }DMA的中断里做三件事关闭DMA通道、拉高CS、置位一个事件标志。主循环检测到事件标志后把双缓冲交换再接着准备下一帧。这套流程下动画刷新对CPU时间占用可以忽略不计。7.2 休眠与低功耗策略小气象站项目往往有电池供电需求。屏幕在不刷新的时候可以让MCU进入Stop模式模组继续维持显示内容。因为OLED没有背光静态画面不会产生额外功耗这一整屏内容只需要提供给驱动芯片的漏电电流而已大约几百微安以内。如果要彻底关屏省电发送0xAE关闭显示再进入Stop模式。唤醒后发0xAF即可恢复不需要重新初始化。但要注意如果唤醒时电荷泵之前被关掉了需要检查初始化状态稳妥做法是在唤醒代码里重新执行整个初始化序列开销也只有几毫秒不值得为省这几毫秒去维护一套状态机。7.3 从单屏到小型GUI的扩展驱动跑通之后下一步自然就是做交互界面。我把这套驱动封装成了类似GUI的最小框架一个屏幕缓冲区、一个事件循环、一组绘制控件函数。显示温湿度数字、画趋势曲线、做菜单切换全部在缓冲上完成刷新只发生在变化区域。做动态曲线时特别能体现缓冲区的价值每来一个新采样点把整条曲线左移一列新的点画在最右列然后只刷新曲线所在的几页区域刷新耗时几乎可以忽略。这套设计对以后换到其他分辨率的屏也友好只需要修改OLED_COLS、页数宏以及初始化里的行数参数接口完全不变。7.4 关于驱动代码移植的建议最后分享一个经验很多网上流传的SH1106驱动代码都能直接套用在这块屏上因为SH1107和SH1106的命令集非常接近。移植时只要保证三点——列地址偏移宏被正确设置、页地址上限改对了、电荷泵命令被保留大部分情况下都能直接跑起来。但如果显示效果和预期有偏差别急着怀疑代码。先做两个自检用0xA5命令把整屏点亮再关闭确认屏的硬件本身没问题再用0xA8配合0x7F确认行数配置这里最容易被疏忽。屏幕硬件特性千差万别代码能跑到稳定状态靠的是一步步按信号和现象排查而不是猜。这套排查方法放到任何一款SH1107模组上都适用。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号