
简介中景园电子1.3英寸OLED技术资料V3.0是一套面向嵌入式开发者、单片机学习者和电子爱好者的官方物料包覆盖从硬件理解到软件上手的完整链路。压缩包约78.65MB内含1.3英寸OLED显示屏原理图、数据手册、模组结构图、测试程序、取字模软件及操作说明并整理了OLED反白显示技术资料和0.96寸/1.3寸IPS彩色屏赠品资料其中例程部分尤其丰富收录20余套针对C51、STM32F103/STM32F030/STM32F407、STM8、MSP430、C8051F、Arduino等主流平台的SPI与IIC接口源码便于在常用开发板上直接移植验证。字模软件与反白说明可辅助生成显示数据、快速实现菜单或字符界面原理图和结构图也能帮助核对引脚封装减少初期接线错误。已有923人学习下载适合正在做OLED显示驱动、菜单界面或低功耗便携设备项目的读者作为参考资料。资源按编号目录归档可快速定位原理图、配置说明与对应芯片例程减少反复搜索和调试时间。1. 中景园电子1.3英寸OLED技术资料V3.0拿到手先别套例程SSD1315和SSD1306不是一回事这块1.3英寸OLED的驱动IC是SSD1315跟0.96寸常见的SSD1306寄存器命令大部分通用但预充电、VCOMH等参数有差别直接复制0.96寸例程会黑屏或花屏。中景园电子1.3英寸OLED技术资料V3.0是一个很完整的官方包包含SSD1315数据手册、硬件参考设计、51/STM32标准库/HAL库/Arduino等软件例程源码还有取模上位机。我拆这个包时把手册、原理图和HAL库例程对着过了一遍发现从零点亮到显示汉字、图片踩完几个坑也就是一晚上。这篇笔记适合手里拿着这块屏、想用STM32F103C8T6或51单片机点亮它的朋友也适合只想找一份可靠的HAL库OLED驱动代码直接移植的工程师。最重要的建议放开头别急着套SSD1306例程先按SSD1315的初始化表走一遍。2. 屏的硬件底细SSD1315的页映射方式与I2C/SPI接口选型2.1 显存不是二维数组128x64背后的Page概念打开SSD1315手册会看到一个GDDRAM的结构图。分辨率128x64没错但GDDRAM的排列不是128行x64列而是8个Page每页128字节每个字节的8个bit正好对应8行像素。页地址模式下写数据时列地址自动加1到达127后停在当前页不会自动翻页。所以写一屏要外层循环8次页地址命令0xB0~0xB7内层写128个字节。这个映射关系直接决定取模方式和绘图函数的写法。比如OLED_ShowChar函数里显示一个8x16的ASCII字符要写两页第一页写字符上半部分8字节第二页写下半部分8字节如果漏掉页1操作字符上下两半会叠在同一页屏幕显示出来就是不完整的乱码。资料包里的例程把这项封装在OLED_Set_Pos(page, col)和OLED_ShowChar里新手一般不会意识到这个“页”的存在等到显示图片错位才回头翻手册。为了避免玄学先自己跑一遍简单的页映射测试不断切换0xB0到0xB7每页只在第0列写一个0x01如果屏上出现8个等距的短横线说明页命令没问题如果数量不对或者间距不对再查列地址命令0x00/0x10的组合。这个测试我习惯放在任何OLED例程移植之前。2.2 I2C还是SPI4pin与7pin的取舍中景园1.3寸OLED一般提供I2C和SPI两个版本。I2C是4pinVCC、GND、SCL、SDA模块上已经焊好上拉电阻和地址选择电阻默认7bit地址0x3C发送时软件里写成0x780x3C左移一位。SPI是7pin多出D/C、CS、RES三根好处是速率上限高SSD1315的SPI接口能跑到10MHz级别而I2C官方最大400kHz。做一个直接的对比表接口引脚数典型速率整屏刷写耗时128x64连续写适合场景I2C4400kHz约45ms含命令开销显示字符、菜单、静态图SPI710MHz约1.3ms波形、动画、快速刷新这里的整屏刷写耗时是我按“每字节9bit含ACK外加列地址设置命令”粗略估算的实际取决于代码里每次传输长度。眼下建议只显示温湿度、把OLED当调试屏输出logI2C够用要做小示波器、FFT频谱、指针动画这种老老实实用SPIDMA。不要把I2C屏硬撑到30帧刷出来也是满屏雪花。2.3 硬性参考设计原理图里那几个电阻和引脚值得看资料包里“硬件参考设计”值得翻开看的不是原理图本身而是模块上几个关键元件的取值。I2C上拉电阻一般是2.2k到10kSPI版本把CS拉到VCC可以固定片选RES脚最好由MCU控制不要悬空。如果板子走线长SDA/SCL上串100~220R电阻能明显减小信号过冲靠近OLED的VCC和GND之间加一个0.1uF去耦电容能解决偶发花屏。原理图里驱动芯片部分会标注SSD1315引脚定义和SSD1306完全兼容这也是为什么很多人会把两者混着用。混着用大概率能点亮但“能点亮”和“稳定显示”之间差着2.4里要讲的参数校准。2.4 初始化序列命令表与SSD1306的差异点初始化序列是OLED例程的根基。资料包里STM32例程的初始化命令我拆出来整理成下面这张表照着烧基本都能亮命令参数作用备注0xAE-关闭显示第一步0xD50x80显示时钟分频/振荡器频率参数越大扫描越快0xA80x3FMultiplex Ratio1/64128x64屏固定0x3F0xD30x00显示偏移0代表不偏移0x40-起始行00x8D0x14开启电荷泵0x10是关闭屏直接不亮0x200x02页地址模式0x00水平、0x01垂直0xA1-段重映射0xA0则左右镜像0xC8-COM扫描方向0xC0则上下镜像0xDA0x12COM引脚硬件配置128x64屏一般固定0x120x810x7F对比度0x00最暗、0xFF最亮0xD90xF1预充电周期SSD1315建议值比SSD1306常用值略高0xDB0x40VCOMH电压屏发虚就找它0xA4-从RAM恢复显示0xA6-正常显示非反色0xAF-开启显示最后一条这里特别注意0xD9和0xDB两行。SSD1306常见例程里0xD9取0x22、0xDB取0x30是正常的但SSD1315上这两个值偏低时屏幕会出现“亮但不透、灰蒙蒙”的症状。资料包例程用0xF1和0x40这是手册对SSD1315的推荐档先按这个跑别急着改。3. Keil下从零复现STM32F103C8T6的HAL库I2C点亮过程3.1 资料包目录结构手册、原理图、例程源码在哪先把V3.0资料包拆开看。目录大致是“1-数据手册”“2-硬件参考设计”“3-程序例程”“4-字模软件”这几个分组。程序例程里按平台再分51单片机一般STC89C52、STM32F103标准库、STM32F103 HAL库、Arduino配合U8g2库等。HAL库版本的核心文件是oled.c和oled.h字库ASCII在font.h里汉字点阵在hz_font.h里如果你要显示自己的汉字需要改hz_font.h并重新用取模软件生成。我一般把“程序例程/STM32_HAL”整个文件夹拷出来CubeMX里按下面配置重新生成一遍再把自己的oled.c和oled.h覆盖进去比直接打开原工程更干净。原工程里还有bsp_i2c.c之类的底层驱动可以参考它的I2C时序。3.2 接线与CubeMX配置F103C8T6的I2C1参数板子和屏接线方向是OLED的VCC接3.3VGND接GNDSCL接PB6SDA接PB7。这块屏不要接5V模块上虽然有稳压但长期5V供电发热明显信号电平和STM32的3.3V也不匹配。用CubeMX生成F103C8T6工程时只需要开I2C1和USART1调试输出用I2C1模式选I2CSpeed Mode选Fast ModeTiming计算可以先默认400kHz。引脚设置里确认SCL和SDA落在PB6/PB7别被CubeMX自动分配到别的引脚。生成代码后在main.c的while(1)之前调用oled_init()。如果用的是软件I2C很多51平台的例程就是GPIO模拟I2CCubeMX的I2C外设就不需要开了直接把例程里的oled.c稍作修改即可。注意软件模拟I2C也保留同一个函数接口OLED_WR_Byte这样上层显示代码不需要动。3.3 驱动代码的三层写命令、写数据、刷显存#include oled.h #include i2c.h #include stm32f1xx_hal.h #define OLED_ADDR_7BIT 0x3C /* 7bit I2C地址模块默认 */ #define OLED_ADDR_WRITE ((OLED_ADDR_7BIT 1)) /* 8bit写地址 0x78 */ void OLED_WR_Byte(uint8_t dat, uint8_t cmd) { uint8_t buf[2]; if (cmd) { buf[0] 0x40; /* 数据控制字节 */ } else { buf[0] 0x00; /* 命令控制字节 */ } buf[1] dat; HAL_I2C_Master_Transmit(hi2c1, OLED_ADDR_WRITE, buf, 2, 100); } void OLED_Set_Pos(uint8_t page, uint8_t col) { OLED_WR_Byte(0xB0 page, 0); /* 页地址0xB0~0xB7 */ OLED_WR_Byte(col 0x0F, 0); /* 列地址低4位 */ OLED_WR_Byte(0x10 | (col 4), 0); /* 列地址高4位 */ } void OLED_Clear(void) { uint8_t page, col; for (page 0; page 8; page) { OLED_Set_Pos(page, 0); for (col 0; col 128; col) { OLED_WR_Byte(0x00, 1); } } } void OLED_ShowChar(uint8_t page, uint8_t col, uint8_t chr) { uint8_t i; const uint8_t *font8x16 OLED_ASCII[chr - ]; OLED_Set_Pos(page, col); for (i 0; i 8; i) { OLED_WR_Byte(font8x16[i], 1); /* 上半部分 */ } OLED_Set_Pos(page 1, col); for (i 8; i 16; i) { OLED_WR_Byte(font8x16[i], 1); /* 下半部分 */ } }逻辑说明OLED_WR_Byte的第一个参数dat是要发送的命令或数据第二个参数cmd为0表示这是命令控制字节0x00cmd为1表示这是数据控制字节0x40。SSD1315在I2C下通过一个控制字节区分后面跟的是命令还是显示RAM数据所以我封装成buf[0]放控制字节、buf[1]放实际内容一次HAL_I2C_Master_Transmit发两个字节。OLED_Set_Pos里0xB0加页号就是页地址命令列地址要按“先低4位、再高4位”分两次发这是SSD1315手册的硬性要求。OLED_Clear和OLED_ShowChar都在页地址模式下工作所以外层一定是先定位页再连续写128字节。参数说明HAL_I2C_Master_Transmit最后一个参数100是超时时间单位ms在400kHz总线正常时2字节传输不到1ms但如果I2C总线上有设备拉死这个函数会一直等最后返回HAL_TIMEOUT。主程序卡在死等的情况要按第5.3节处理。地址为什么要左移一位HAL库的I2C接口用的是8bit地址最低位是读写位所以0x3C必须左移成0x78。3.4 main函数流程上电时序的先后顺序main函数里流程大概是HAL_Init() - 系统时钟配置 - MX_GPIO_Init() - MX_I2C1_Init() - OLED_Init() - OLED_Clear() - OLED_ShowString(0, 0, Hello OLED)。我在实际做的时候会在MX_I2C1_Init()和OLED_Init()之间加一个HAL_Delay(200)让屏模块电源稳定后再发初始化命令。第一次上电如果初始化失败后面再怎么刷都是黑屏因为SSD1315的GDDRAM状态是随机的必须先跑完整初始化序列把显示开关打开。还有一个细节OLED_Init()函数最后一步是OLED_WR_Byte(0xAF, 0)也就是打开显示如果中途MCU要跑很久的延时任务建议在进入低功耗前发0xAE关闭显示这样能省几百uA电流也能减少残影。如果需要跑自己的汉字字符串HAL库例程里一般有OLED_ShowChinese(page, col, index)这样的函数它从hz_font.h里按序号取出16x16点阵调用OLED_Set_Pos两次。这个函数依赖字库数组的顺序所以新增汉字后记得调整序号索引不要自己乱插否则显示出来的汉字是对不上的。4. 图片、汉字、波形取模参数与三种常见的显示需求4.1 取模软件参数先从16x16汉字开始资料包里给的字模软件一般叫“PCtoLCD2002”或类似的上位机这类工具的功能是位图转C数组。真正需要花心思的不是操作而是参数组合点阵格式阴码1亮0灭OLED是电流驱动阴码直观取模方式逐行式输出进制十六进制方向高位在前附加说明去掉“自定义格式”和“前缀后缀”直接输出标准数组按上面设置生成一个16x16“中”字的点阵数组大致是const uint8_t hz_zhong[32] { 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x3F, 0xFF, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };注意32个字节恰好对应16行、每行16bit。逐行式取模得到的数据是按图像自上而下、每行左边到右边排的但OLED页地址显存是按页排的16x16汉字正好分为页0行0~7和页1行8~15。所以OLED_ShowChinese的实现里不能直接把数组按顺序写到同一页必须做“隔行重组”数组中前16字节是行0~7的给页0后16字节是行8~15的给页1。如果取模时改成“列行式”甚至“按页取模”生成出来的数组就是按页排好的写屏时直接连续拷贝即可。这是很容易被忽略的参数坑很多“图片显示倒着、斜着”的帖子根子都在这里。4.2 图片显示128x64全屏BMP的搬运函数图片一般由电脑上的取模软件把bmp转成一个数组。128x64的单色bmp在“逐行式阴码”下会生成1024字节。如果取模软件支持“12864 OLED专用格式”它输出的数组基本是按页序的直接调用OLED_DrawBMP就能显示。写屏函数我习惯这样写void OLED_DrawBMP(uint8_t page_start, uint8_t col_start, const uint8_t *bmp, uint8_t width, uint8_t height) { uint8_t i, j; for (i 0; i height / 8; i) { OLED_Set_Pos(page_start i, col_start); for (j 0; j width; j) { OLED_WR_Byte(bmp[i * width j], 1); } } }逻辑说明函数假定传入的数组是按“页优先”组织的每页width个字节。外层循环按页推进内层循环从col_start开始连续写width个字节。OLED硬件列地址自动加1所以内层不需要重发列地址。参数里width填128、height填64page_start和col_start可以指定局部显示区域。如果要局部刷新一个32x16窗口就把起始页和起始列传进去配合一个只包含该区域点阵的数组即可速度比全屏刷新快很多。4.3 动态波形列扫描方式与页扫描方式的区别做OLED小示波器和滚动频谱时采样值要实时显示。一个完整的波形刷新函数是这样void OLED_UpdateWave(const uint8_t *wave_data) { uint8_t page, col; for (col 0; col 128; col) { for (page 0; page 8; page) { OLED_Set_Pos(page, col); OLED_WR_Byte(wave_data[page * 128 col], 1); } } }wave_data是一个8*128的数组按页优先组织。外层循环是列内层循环是页这样同一列的8个页连续写入画面不会出现跨页撕裂如果外层按页、内层按列遇到快速移动的波形边缘上下页会明显错开几毫秒。由于每次都要重发页地址和列地址I2C下这个函数实际耗时会比理论值高所以滚动波形建议用SPIDMA并在RAM里维护一份完整的显存buf。每次采样后先更新buf再一次性把整个buf推到屏上帧率能上一个台阶。5. 常见问题排查黑屏、花屏、I2C死锁和屏“玄学”故障5.1 黑屏且“屏绝对没坏”先查电源复位再查初始化收尾现象代码烧录了接线核对了几遍屏黑得彻底。原因VCC没到3.3V是常见的低级错误另一个常见原因是RES脚一直为低驱动IC一直处于复位状态资料包例程里RES通常接MCU的PB0或模块上电自动复位但如果你把RES悬空很多模块根本不会自己拉高复位完成。解决给RES脚接一个10k上拉到VCC或者干脆在初始化序列最前面加一段软复位先拉低RES至少10us再拉高延时10ms后再发初始化命令。同时检查初始化数组是不是漏了最后一条0xAF。这招能解决七成“新屏黑屏”的问题。5.2 白屏或发虚对比度低得像蒙了一层雾现象屏亮了但文字颜色很浅背景也是灰的像没睡醒。原因0x81对比度寄存器、0xD9预充电、0xDB VCOMH三者的组合不对。很多SSD1306例程里0x81给0xCF在1.3寸SSD1315上会显得发白因为COM电压和预充电能力不一样。解决按资料包的推荐值设置0x81 0x7F0xD9 0xF10xDB 0x40。不同批次的屏可能还需要微调0x81调到显示清晰且背景不太亮为止。如果用U8g2库注意U8g2的SSD1306配置不会自动适配SSD1315出现这个现象时不要改U8g2直接在初始化回调里覆盖这三个寄存器值。5.3 I2C总线死锁SDA被拉低、HAL_I2C_Master_Transmit卡死现象程序跑着跑着卡在某个OLED操作里断点打进去发现停在HAL_I2C_Master_Transmit超时上或者上电后第一次跑正常断电重启就卡。原因OLED模块的SDA被从机拉死。常见场景是引入低功耗后上电顺序变化模块先掉电而MCU还活着I2C总线上出现“半活”设备把SDA钳低。HAL库只会反复重发STOP不会自动复位I2C外设。解决最稳的是改用软件模拟I2C资料包51例程里就是软件模拟GPIO操作完全可控不会有外设死锁。如果坚持用硬件I2C在每次OLED通信前加超时判断超时后调用HAL_I2C_DeInit和重新HAL_I2C_Init把外设复位。再一个实用招OLED的VCC不要和MCU共用一个LDO断电顺序就不会互相牵扯。遇到“上电时序导致的偶发花屏”基本都和这个有关。5.4 从0.96寸项目复制代码1.3寸屏显示错位现象同样的代码在0.96寸OLED上正常换到1.3寸后字符错位、图片撕裂、上下半屏颠倒。原因0.96寸多数是SSD13061.3寸是SSD1315。命令格式里0xA0/A1段重映射、0xC0/C8COM扫描方向和0xDACOM引脚配置三者组合决定了显存方向和屏幕物理方向是否一致。0.96寸常用0xA00xC00xDA 0x121.3寸资料包常用0xA10xC80xDA 0x12方向完全反过来。解决不要整体复制SSD1306的初始化表直接用手册里的SSD1315表如果坚持用SSD1306库把0xA0改成0xA1、0xC0改成0xC8显示左右上下就正常了。不同厂家的1.3寸屏段映射和COM扫描方向可能出厂就不同所以最好的习惯是准备一段“全屏十字线”测试代码显示第0行和第63行横线、第0列和第127列竖线通过判断哪条线出现在哪个物理位置来确认本屏的方向配置一劳永逸。5.5 刷新闪屏与残影不是算法问题是接口和取模的问题现象动态刷新时屏幕闪烁静止画面几分钟后留下轻微残影。原因I2C上频繁整屏刷新刷新率太低视觉闪烁OLED长时间显示同一画面发光材料衰减不一致产生类似“烧屏”的残影。解决静态界面用局部刷新只更新变化区域别整屏无脑刷动态波形用SPIDMA并做好帧率控制别让刷新间隔出现明显抖动。残影这块如果产品长期亮同一画面建议启动屏幕保护10秒无操作后切换一次屏幕内容或者直接发0xAE关屏需要看数据时再0xAF打开。低成本OLED面板并不是不会烧屏1.3寸这种屏尤其注意。6. 进阶验证技巧白屏测试十字线法30秒定位屏的“脾气”新屏到手我做第一件事不是跑资料包Demo而是烧一段白屏测试。全屏写0xFF屏应该整块亮起来再全屏写0x00整块全灭。这段代码不需要字库、不需要取模软件只要I2C地址正确就能看到效果void OLED_ScreenTestAll(void) { uint8_t page, col, cur, val; for (cur 0; cur 2; cur) { val (cur 0) ? 0x00 : 0xFF; for (page 0; page 8; page) { OLED_Set_Pos(page, 0); for (col 0; col 128; col) { OLED_WR_Byte(val, 1); } } HAL_Delay(500); } }这段代码足够直观第一次循环写0x00屏全灭第二次写0xFF屏全亮。如果全亮时出现某个页面整页不亮问题多半在页地址命令0xB0~0xB7而不是屏坏了如果全灭时某个页面有亮点那可能是取模工具或刷屏顺序造成的残留。白屏测试通过后再写一组十字线函数确认方向。设置四个点左上角(0,0)、右上角(0,127)、左下角(63,0)、右下角(63,127)然后判断这四个点在物理屏上的位置就知道段重映射和COM扫描方向到底是正还是反了。用这套方法我帮同事排查过一次“同型号不同批次”乱码问题。当时他的板子焊完之后只有一半屏正常另外一半整列花掉现象很像驱动IC坏了。用白屏测试一看花掉的那一半全亮另一半全灭说明是页地址命令被后面的数据覆盖跟着查代码发现有个地方OLED_Set_Pos的page传参超过7数组越界写坏了。这就是很典型的“看起来像硬件问题其实是代码越界”的案例。从那以后我拿到任何新屏都是先白屏测试、再十字线验证方向确认这两个硬指标之后才敢往上叠字库和图片。这套V3.0资料包里还带了原理图PDF、取模软件和多个平台的例程源码配合上面这个方法从零点亮一块新屏通常不用半小时。希望帮到你。本文还有配套的精品资源点击获取