【I²C 总线】OLED 屏幕
下载例程代码: 下载代码
请一定按照 例程使用方法 🔗 导入例程,否则下载的可能不是例程而是其他工程。
OLED 屏幕(I2C_OLED)
在 OLED 屏幕上显示文字、图形和 BMP 图像
板载 OLED 规格:
| 参数 | 值 |
|---|---|
| 芯片型号 | 芯颖科技 CH1116 |
| 分辨率 | 128 × 64 |
| 屏幕尺寸 | 1.3 英寸 |
| I²C 地址 | 0x7A |
如何使用例程
编译并下载程序到学习板,即可看到程序效果:
OLED 屏幕循环显示不同画面:
- 汉字显示(反色)、中英文混合字符串显示、符号字符串显示
- 变量显示
- 绘制直线演示
- 绘制(空心)矩形演示
- 绘制(空心)圆形演示
- 显示 bmp 图像

例程讲解
下面介绍了如何自己实现该例程的功能
1、工程配置
- 开启外部晶振:在 Pinout&Configuration -> System Core -> RCC 页面,将 High Speed Clock (HSE) 配置为 Crystal/Ceramic Resonator

- 配置时钟频率:在 Clock Configuration 页面,将 PLL Source 选择为 HSE,将 System Clock Mux 选择为 PLLCLK,然后在 HCLK (MHz) 输入 72 并回车,将 HCLK 频率配置为 72 MHz

- 配置 I²C1:在
I2C1配置页,将 I2C 模式选择为I2C,并在下方Parameter Settings将I2C Speed Mode选择为Fast Mode

- 配置生成单独.c/.h 文件:在 Project Manager -> Code Generator 页面中,勾选 Generate peripheral initialization as ... per peripheral
2、代码
(1) 初始化过程
-
拷贝库文件:将 oled.c、font.c 文件拷贝到 Core -> Src 目录下,将 oled.h、font.h 文件拷贝到 Core -> Inc 目录下。
-
在 main.c 中添加 include:
#include "string.h"
#include "oled.h"
#include "stdio.h" -
初始化 OLED:
HAL_Delay(20); // 单片机启动比OLED上电快,需要延迟等待一下
OLED_Init(); // 初始化OLED
(2) 显示函数
-
将缓存内容更新到屏幕显示:
OLED_ShowFrame();提示任何操作都需要调用此函数才能显示到屏幕上,否则只是改变显示缓冲区
-
新建空白缓冲区:
OLED_NewFrame();提示只存在一个 Frame,NewFrame 后之前的内容将被清空
-
显示一个像素点:
uint8_t x横坐标uint8_t y纵坐标OLED_ColorMode mode颜色模式OLED_COLOR_NORMAL正常OLED_COLOR_REVERSE反色
void OLED_SetPixel(uint8_t x, uint8_t y, OLED_ColorMode color);
// 示例
OLED_NewFrame(); // 新建一个空白缓冲区
OLED_SetPixel(0, 0, OLED_COLOR_NORMAL); // 在(0, 0)处显示一个黑色的像素点
OLED_ShowFrame(); // 将缓冲区内容显示到屏幕上
- 显示字符串
uint8_t x纵坐标 [0, 127]uint8_t y纵坐标 [0, 63]char *str要显示的字符串const Font *font字体OLED_ColorMode color颜色模式
void OLED_PrintString(uint8_t x, uint8_t y, char *str, const Font *font, OLED_ColorMode color);
// 示例
OLED_NewFrame(); // 新建一个空白缓冲区
OLED_PrintString(0, 22, "B站-KEYSKING", &font16x16, OLED_COLOR_NORMAL); // 中文、英文、符号混合显示
OLED_ShowFrame(); // 将缓冲区内容显示到屏幕上
- 绘制直线:
uint8_t x1直线起点横坐标 [0, 127]uint8_t y1直线起点纵坐标 [0, 63]uint8_t x2直线终点横坐标 [0, 127]uint8_t y2直线终点纵坐标 [0, 63]OLED_ColorMode color颜色模式
void OLED_DrawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, OLED_ColorMode color);
// 示例
OLED_NewFrame(); // 新建一个空白缓冲区
OLED_DrawLine(0, 0, 127, 63, OLED_COLOR_NORMAL); // 从左上角到右下角绘制一条直线
OLED_ShowFrame(); // 将缓冲区内容显示到屏幕上
- 绘制(空心)矩形:
uint8_t x起始点横坐标 [0, 127]uint8_t y起始点纵坐标 [0, 63]uint8_t w矩形宽度 [0, 127]uint8_t h矩形高度 [0, 63]OLED_ColorMode color颜色模式
void OLED_DrawRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, OLED_ColorMode color);
// 示例
OLED_NewFrame(); // 新建一个空白缓冲区
OLED_DrawRectangle(32, 16, 63, 31, OLED_COLOR_NORMAL); // 绘制一个空心矩形
OLED_ShowFrame(); // 将缓冲区内容显示到屏幕上
- 绘制(填充)矩形:
uint8_t x起始点横坐标 [0, 127]uint8_t y起始点纵坐标 [0, 63]uint8_t w矩形宽度 [0, 127]uint8_t h矩形高度 [0, 63]OLED_ColorMode color颜色模式
void OLED_DrawFilledRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, OLED_ColorMode color);
// 示例
OLED_NewFrame(); // 新建一个空白缓冲区
OLED_DrawFilledRectangle(32, 16, 63, 31, OLED_COLOR_NORMAL); // 绘制一个填充矩形
OLED_ShowFrame(); // 将缓冲区内容显示到屏幕上
-
绘制(空心)圆形:
此函数使用 Bresenham 算法绘制圆
uint8_t x圆心横坐标 [0, 127]uint8_t y圆心纵坐标 [0, 63]uint8_t r圆的半径 [0, 63]OLED_ColorMode color颜色模式
void OLED_DrawCircle(uint8_t x, uint8_t y, uint8_t r, OLED_ColorMode color);
// 示例
OLED_NewFrame(); // 新建一个空白缓冲区
OLED_DrawCircle(64, 32, 16, OLED_COLOR_NORMAL); // 绘制一个空心圆形
OLED_ShowFrame(); // 将缓冲区内容显示到屏幕上
-
绘制(填充)圆形:
此函数使用 Bresenham 算法绘制圆
uint8_t x圆心横坐标 [0, 127]uint8_t y圆心纵坐标 [0, 63]uint8_t r圆的半径 [0, 63]OLED_ColorMode color颜色模式
void OLED_DrawFilledCircle(uint8_t x, uint8_t y, uint8_t r, OLED_ColorMode color);
// 示例
OLED_NewFrame(); // 新建一个空白缓冲区
OLED_DrawFilledCircle(64, 32, 16, OLED_COLOR_NORMAL); // 绘制一个填充圆形
OLED_ShowFrame(); // 将缓冲区内容显示到屏幕上
- 绘制(空心)三角形:
uint8_t x1第一个点横坐标 [0, 127]uint8_t y1第一个点纵坐标 [0, 63]uint8_t x2第二个点横坐标 [0, 127]uint8_t y2第二个点纵坐标 [0, 63]uint8_t x3第三个点横坐标 [0, 127]uint8_t y3第三个点纵坐标 [0, 63]OLED_ColorMode color颜色模式
void OLED_DrawTriangle(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t x3, uint8_t y3, OLED_ColorMode color);
// 示例
OLED_NewFrame(); // 新建一个空白缓冲区
OLED_DrawTriangle(64, 0, 0, 63, 127, 63, OLED_COLOR_NORMAL); // 在屏幕中心绘制一个空心三角形
OLED_ShowFrame(); // 将缓冲区内容显示到屏幕上
- 绘制(填充)三角形:
uint8_t x1第一个点横坐标 [0, 127]uint8_t y1第一个点纵坐标 [0, 63]uint8_t x2第二个点横坐标 [0, 127]uint8_t y2第二个点纵坐标 [0, 63]uint8_t x3第三个点横坐标 [0, 127]uint8_t y3第三个点纵坐标 [0, 63]OLED_ColorMode color颜色模式
void OLED_DrawFilledTriangle(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t x3, uint8_t y3, OLED_ColorMode color);
// 示例
OLED_NewFrame(); // 新建一个空白缓冲区
OLED_DrawFilledTriangle(64, 0, 0, 63, 127, 63, OLED_COLOR_NORMAL); // 在屏幕中心绘制一个填充三角形
OLED_ShowFrame(); // 将缓冲区内容显示到屏幕上
- 绘制(空心)椭圆:
uint8_t x圆心横坐标 [0, 127]uint8_t y圆心纵坐标 [0, 63]uint8_t a长轴长度uint8_t b短轴长度OLED_ColorMode color颜色模式
void OLED_DrawEllipse(uint8_t x, uint8_t y, uint8_t a, uint8_t b, OLED_ColorMode color)
// 示例
OLED_NewFrame(); // 新建一个空白缓冲区
OLED_DrawEllipse(64, 32, 30, 15, OLED_COLOR_NORMAL); // 绘制一个空心椭圆
OLED_ShowFrame(); // 将缓冲区内容显示到屏幕上
- 显示 BMP 图像:
uint8_t x起始点横坐标 [0, 127]uint8_t y起始点纵坐标 [0, 63]const Image *img图像数据OLED_ColorMode color颜色模式
void OLED_DrawImage(uint8_t x, uint8_t y, const Image *img, OLED_ColorMode color);
// 示例
OLED_NewFrame(); // 新建一个空白缓冲区
OLED_DrawImage((128 - (bilibiliImg.w)) / 2, 0, &bilibiliImg, OLED_COLOR_NORMAL); // 显示名为bilibiliImg的BMP图像
OLED_ShowFrame(); // 将缓冲区内容显示到屏幕上
(3) 取字模
文字:分为两类:ASCII 字符、中文字符。
-
ASCII 字符:font.c 库中已包含,可以直接调用
-
包含 8、12、16、24 四种大小的字体
-
每种字体均有 95 个可打印字符
提示具体请参考 小智精灵 串口助手 中的 ASCII 码表
-
-
中文字符:中文字符数量多,STM32 内部 Flash 无法全部存储,因此需要根据使用的字符来取字模。
- 在线取字模工具:https://led.zhxy.net/
- 使用方法
- 输入所有需要用到的中文字符后,点击右下角复制按钮,复制字模
- 将字模代码粘贴到 font.c 中,并在 font.h 中添加对应的声明
- 使用 OLED_PrintString 函数, 传入对应的字体结构体即可显示中文字符
图片:支持 BMP 格式单色位图
- 在线取图模工具:https://led.zhxy.net/

(4) 额外的内容
- 小恐龙游戏:https://led.zhxy.net/

- SSD1306 驱动库:https://led.zhxy.net/

故障排除
屏幕显示偏暗
-
不要在 STM32 程序启动时马上初始化 OLED
刚上电时 STM32 比 OLED 启动快,立即对 OLED 进行初始化可能会失败。
延时 10-50 毫秒再调用
OLED_Init()函数即可。
cube 重新生成代码后,中文出现乱码
-
cubeIDE 对中文支持的问题,添加环境变量可以解决(仅 Windows 下)
- 点击开始菜单,输入“环境变量”搜索,进入系统属性设置

-
点击系统属性下方的“环境变量”,进入环境变量配置页面。如图,点击新建,添加一个环境变量并保存即可。
变量名:JAVA_TOOL_OPTIONS
变量值:-Dfile.encoding=UTF-8
