ESP-C3入门21. 点亮1306驱动的OLED屏
- 一、Espressif/ssd1306 驱动简介
- 1. 驱动介绍
- 2. OLED充电泵概念
- 二、I2C 通讯步骤
- 1. 初始化 I2C 总线 (i2c_master_init()函数):
- 2. 创建 I2C 命令句柄 (i2c_cmd_handle_t cmd = i2c_cmd_link_create()):
- 3. 发送启动信号 (i2c_master_start(cmd)):
- 4. 写入字节数据 (i2c_master_write_byte(cmd, data, ACK)):
- 5. 写入命令和数据:
- 6. 发送停止信号 (i2c_master_stop(cmd)):
- 7. 执行 I2C 命令序列 (i2c_master_cmd_begin(I2C_NUM_0, cmd, timeout)):
- 8. 删除命令句柄 (i2c_cmd_link_delete(cmd)):
- 三、通讯demo,点亮OLED屏
- 1. ssd1366.h
- 2. font8x8_basic.h
- 3. i2c 操作示例 main.c
- 四、Espressif 官方的 ssd1306驱动使用方法
- 1. 使用idf.py命令加载库
- 2. 下载源码加入工程
- 3. main.c 实例
一、Espressif/ssd1306 驱动简介
1. 驱动介绍
地址:
https://components.espressif.com/components/espressif/ssd1306
Espressif/ssd1306 是 Espressif Systems 开发的用于 SSD1306 驱动芯片的库,用于在 ESP32 和 ESP8266 上控制 SSD1306 型号的 OLED 显示屏。这个库提供了一组函数和接口,使得开发者可以在 ESP-IDF 框架中方便地控制和管理这种类型的 OLED 显示屏。
以下是 Espressif/ssd1306 库的一些主要特点和功能:
- OLED 控制:该库允许你控制 SSD1306 驱动的 OLED 显示屏,包括初始化、绘制图像、显示文本等。
- 支持 I2C 和 SPI 接口:该库支持使用 I2C 和 SPI 接口来与 OLED 显示屏通信。你可以根据你的项目需要选择适当的接口。
- 支持多种显示模式:Espressif/ssd1306 库支持多种显示模式,如水平、垂直滚动、反显等。
- 使用 C 语言:该库是用 C 语言编写的,与 ESP-IDF 框架相匹配,可在 ESP32 和 ESP8266 上使用。
- 开源:Espressif/ssd1306 是开源项目,你可以在 GitHub 上找到它的源代码,查看其源代码、示例和文档。
2. OLED充电泵概念
“Set Charge Pump Enable” 是 OLED 显示屏初始化过程中的一个命令,用于控制显示屏内部的电荷泵电路是否启用。电荷泵电路是一种电路,可以将较低的电压转换为较高的电压,从而在不增加外部电源电压的情况下,为OLED显示屏提供所需的高压驱动。
在OLED显示屏中,显示像素需要一定的驱动电压,通常比较高。电荷泵电路的作用是通过将低电压转换为高电压,为显示屏提供驱动所需的电压。这样可以减少对外部电源的依赖,使得OLED显示屏可以使用更低的外部电压进行工作。
在"Set Charge Pump Enable" 命令中,设置充电泵为启用状态,可以确保OLED显示屏的驱动电路正常工作,从而正常显示图像和文字。如果充电泵未启用,可能会导致显示屏无法正常驱动,造成屏幕无法显示或显示异常的问题。
二、I2C 通讯步骤
在 ESP-IDF 中使用 I2C 进行通信的步骤如下:
1. 初始化 I2C 总线 (i2c_master_init()函数):
首先,配置 I2C 总线的基本参数,例如模式、SDA 和 SCL 引脚、上拉电阻等。使用 i2c_param_config() 函数设置这些参数,然后调用 i2c_driver_install() 安装 I2C 驱动。
2. 创建 I2C 命令句柄 (i2c_cmd_handle_t cmd = i2c_cmd_link_create()):
使用 i2c_cmd_link_create() 函数创建一个用于构建 I2C 命令序列的命令句柄。
3. 发送启动信号 (i2c_master_start(cmd)):
在开始通信前,发送启动信号,表示新的传输事务即将开始。
4. 写入字节数据 (i2c_master_write_byte(cmd, data, ACK)):
通过 i2c_master_write_byte() 函数将字节数据写入 I2C 总线。data 参数是要发送的数据字节,ACK 参数用于控制是否发送应答信号。
5. 写入命令和数据:
利用连续的 i2c_master_write_byte() 调用,写入 OLED 屏幕的控制命令和显示数据。
6. 发送停止信号 (i2c_master_stop(cmd)):
传输完成后,发送停止信号,表示通信结束。
7. 执行 I2C 命令序列 (i2c_master_cmd_begin(I2C_NUM_0, cmd, timeout)):
使用 i2c_master_cmd_begin() 函数将构建的命令序列发送到 I2C 总线并等待执行结果。
8. 删除命令句柄 (i2c_cmd_link_delete(cmd)):
在通信完成后,使用 i2c_cmd_link_delete() 函数释放创建的命令句柄,以备后续使用。
这些步骤允许ESP32与 OLED 屏幕或其他外部设备进行可靠的通信。
三、通讯demo,点亮OLED屏
下面的示例用到 两个网上的头文件, 内容里写了引用链接。
1. ssd1366.h
#ifndef MAIN_SSD1366_H_
#define MAIN_SSD1366_H_// Following definitions are bollowed from
// http://robotcantalk.blogspot.com/2015/03/interfacing-arduino-with-ssd1306-driven.html// SLA (0x3C) + WRITE_MODE (0x00) = 0x78 (0b01111000)
#define OLED_I2C_ADDRESS 0x3C// Control byte
#define OLED_CONTROL_BYTE_CMD_SINGLE 0x80
#define OLED_CONTROL_BYTE_CMD_STREAM 0x00
#define OLED_CONTROL_BYTE_DATA_STREAM 0x40// Fundamental commands (pg.28)
#define OLED_CMD_SET_CONTRAST 0x81 // follow with 0x7F
#define OLED_CMD_DISPLAY_RAM 0xA4
#define OLED_CMD_DISPLAY_ALLON 0xA5
#define OLED_CMD_DISPLAY_NORMAL 0xA6
#define OLED_CMD_DISPLAY_INVERTED 0xA7
#define OLED_CMD_DISPLAY_OFF 0xAE
#define OLED_CMD_DISPLAY_ON 0xAF// Addressing Command Table (pg.30)
#define OLED_CMD_SET_MEMORY_ADDR_MODE 0x20 // follow with 0x00 = HORZ mode = Behave like a KS108 graphic LCD
#define OLED_CMD_SET_COLUMN_RANGE 0x21 // can be used only in HORZ/VERT mode - follow with 0x00 and 0x7F = COL127
#define OLED_CMD_SET_PAGE_RANGE 0x22 // can be used only in HORZ/VERT mode - follow with 0x00 and 0x07 = PAGE7// Hardware Config (pg.31)
#define OLED_CMD_SET_DISPLAY_START_LINE 0x40
#define OLED_CMD_SET_SEGMENT_REMAP 0xA1
#define OLED_CMD_SET_MUX_RATIO 0xA8 // follow with 0x3F = 64 MUX
#define OLED_CMD_SET_COM_SCAN_MODE 0xC8
#define OLED_CMD_SET_DISPLAY_OFFSET 0xD3 // follow with 0x00
#define OLED_CMD_SET_COM_PIN_MAP 0xDA // follow with 0x12
#define OLED_CMD_NOP 0xE3 // NOP// Timing and Driving Scheme (pg.32)
#define OLED_CMD_SET_DISPLAY_CLK_DIV 0xD5 // follow with 0x80
#define OLED_CMD_SET_PRECHARGE 0xD9 // follow with 0xF1
#define OLED_CMD_SET_VCOMH_DESELCT 0xDB // follow with 0x30// Charge Pump (pg.62)
#define OLED_CMD_SET_CHARGE_PUMP 0x8D // follow with 0x14#endif /* MAIN_SSD1366_H_ */
2. font8x8_basic.h
/** font8x8_basic.h** Created on: 2017/05/03* Author: yanbe*/#ifndef MAIN_FONT8X8_BASIC_H_
#define MAIN_FONT8X8_BASIC_H_/*Constant: font8x8_basic_trContains an 90 digree transposed 8x8 font map for unicode pointsU+0000 - U+007F (basic latin)To make it easy to use with SSD1306's GDDRAM mapping and API,this constant is an 90 degree transposed.The original version written by Marcel Sondaar is availble at:https://github.com/dhepper/font8x8/blob/master/font8x8_basic.hConversion is done via following procedure:for (int code = 0; code < 128; code++) {uint8_t trans[8];for (int w = 0; w < 8; w++) {trans[w] = 0x00;for (int b = 0; b < 8; b++) {trans[w] |= ((font8x8_basic[code][b] & (1 << w)) >> w) << b;}}for (int w = 0; w < 8; w++) {if (w == 0) { printf(" { "); }printf("0x%.2X", trans[w]);if (w < 7) { printf(", "); }if (w == 7) { printf(" }, // U+00%.2X (%c)\n", code, code); }}}
*/uint8_t font8x8_basic_tr[128][8] = {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0000 (nul){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0001{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0002{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0003{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0004{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0005{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0006{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0007{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0008{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0009{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000A{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000B{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000C{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000D{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000E{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000F{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0010{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0011{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0012{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0013{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0014{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0015{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0016{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0017{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0018{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0019{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001A{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001B{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001C{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001D{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001E{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001F{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0020 (space){ 0x00, 0x00, 0x06, 0x5F, 0x5F, 0x06, 0x00, 0x00 }, // U+0021 (!){ 0x00, 0x03, 0x03, 0x00, 0x03, 0x03, 0x00, 0x00 }, // U+0022 ("){ 0x14, 0x7F, 0x7F, 0x14, 0x7F, 0x7F, 0x14, 0x00 }, // U+0023 (#){ 0x24, 0x2E, 0x6B, 0x6B, 0x3A, 0x12, 0x00, 0x00 }, // U+0024 ($){ 0x46, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x62, 0x00 }, // U+0025 (%){ 0x30, 0x7A, 0x4F, 0x5D, 0x37, 0x7A, 0x48, 0x00 }, // U+0026 (&){ 0x04, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0027 ('){ 0x00, 0x1C, 0x3E, 0x63, 0x41, 0x00, 0x00, 0x00 }, // U+0028 ((){ 0x00, 0x41, 0x63, 0x3E, 0x1C, 0x00, 0x00, 0x00 }, // U+0029 ()){ 0x08, 0x2A, 0x3E, 0x1C, 0x1C, 0x3E, 0x2A, 0x08 }, // U+002A (*){ 0x08, 0x08, 0x3E, 0x3E, 0x08, 0x08, 0x00, 0x00 }, // U+002B (+){ 0x00, 0x80, 0xE0, 0x60, 0x00, 0x00, 0x00, 0x00 }, // U+002C (,){ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00 }, // U+002D (-){ 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00 }, // U+002E (.){ 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00 }, // U+002F (/){ 0x3E, 0x7F, 0x71, 0x59, 0x4D, 0x7F, 0x3E, 0x00 }, // U+0030 (0){ 0x40, 0x42, 0x7F, 0x7F, 0x40, 0x40, 0x00, 0x00 }, // U+0031 (1){ 0x62, 0x73, 0x59, 0x49, 0x6F, 0x66, 0x00, 0x00 }, // U+0032 (2){ 0x22, 0x63, 0x49, 0x49, 0x7F, 0x36, 0x00, 0x00 }, // U+0033 (3){ 0x18, 0x1C, 0x16, 0x53, 0x7F, 0x7F, 0x50, 0x00 }, // U+0034 (4){ 0x27, 0x67, 0x45, 0x45, 0x7D, 0x39, 0x00, 0x00 }, // U+0035 (5){ 0x3C, 0x7E, 0x4B, 0x49, 0x79, 0x30, 0x00, 0x00 }, // U+0036 (6){ 0x03, 0x03, 0x71, 0x79, 0x0F, 0x07, 0x00, 0x00 }, // U+0037 (7){ 0x36, 0x7F, 0x49, 0x49, 0x7F, 0x36, 0x00, 0x00 }, // U+0038 (8){ 0x06, 0x4F, 0x49, 0x69, 0x3F, 0x1E, 0x00, 0x00 }, // U+0039 (9){ 0x00, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }, // U+003A (:){ 0x00, 0x80, 0xE6, 0x66, 0x00, 0x00, 0x00, 0x00 }, // U+003B (;){ 0x08, 0x1C, 0x36, 0x63, 0x41, 0x00, 0x00, 0x00 }, // U+003C (<){ 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00 }, // U+003D (=){ 0x00, 0x41, 0x63, 0x36, 0x1C, 0x08, 0x00, 0x00 }, // U+003E (>){ 0x02, 0x03, 0x51, 0x59, 0x0F, 0x06, 0x00, 0x00 }, // U+003F (?){ 0x3E, 0x7F, 0x41, 0x5D, 0x5D, 0x1F, 0x1E, 0x00 }, // U+0040 (@){ 0x7C, 0x7E, 0x13, 0x13, 0x7E, 0x7C, 0x00, 0x00 }, // U+0041 (A){ 0x41, 0x7F, 0x7F, 0x49, 0x49, 0x7F, 0x36, 0x00 }, // U+0042 (B){ 0x1C, 0x3E, 0x63, 0x41, 0x41, 0x63, 0x22, 0x00 }, // U+0043 (C){ 0x41, 0x7F, 0x7F, 0x41, 0x63, 0x3E, 0x1C, 0x00 }, // U+0044 (D){ 0x41, 0x7F, 0x7F, 0x49, 0x5D, 0x41, 0x63, 0x00 }, // U+0045 (E){ 0x41, 0x7F, 0x7F, 0x49, 0x1D, 0x01, 0x03, 0x00 }, // U+0046 (F){ 0x1C, 0x3E, 0x63, 0x41, 0x51, 0x73, 0x72, 0x00 }, // U+0047 (G){ 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00 }, // U+0048 (H){ 0x00, 0x41, 0x7F, 0x7F, 0x41, 0x00, 0x00, 0x00 }, // U+0049 (I){ 0x30, 0x70, 0x40, 0x41, 0x7F, 0x3F, 0x01, 0x00 }, // U+004A (J){ 0x41, 0x7F, 0x7F, 0x08, 0x1C, 0x77, 0x63, 0x00 }, // U+004B (K){ 0x41, 0x7F, 0x7F, 0x41, 0x40, 0x60, 0x70, 0x00 }, // U+004C (L){ 0x7F, 0x7F, 0x0E, 0x1C, 0x0E, 0x7F, 0x7F, 0x00 }, // U+004D (M){ 0x7F, 0x7F, 0x06, 0x0C, 0x18, 0x7F, 0x7F, 0x00 }, // U+004E (N){ 0x1C, 0x3E, 0x63, 0x41, 0x63, 0x3E, 0x1C, 0x00 }, // U+004F (O){ 0x41, 0x7F, 0x7F, 0x49, 0x09, 0x0F, 0x06, 0x00 }, // U+0050 (P){ 0x1E, 0x3F, 0x21, 0x71, 0x7F, 0x5E, 0x00, 0x00 }, // U+0051 (Q){ 0x41, 0x7F, 0x7F, 0x09, 0x19, 0x7F, 0x66, 0x00 }, // U+0052 (R){ 0x26, 0x6F, 0x4D, 0x59, 0x73, 0x32, 0x00, 0x00 }, // U+0053 (S){ 0x03, 0x41, 0x7F, 0x7F, 0x41, 0x03, 0x00, 0x00 }, // U+0054 (T){ 0x7F, 0x7F, 0x40, 0x40, 0x7F, 0x7F, 0x00, 0x00 }, // U+0055 (U){ 0x1F, 0x3F, 0x60, 0x60, 0x3F, 0x1F, 0x00, 0x00 }, // U+0056 (V){ 0x7F, 0x7F, 0x30, 0x18, 0x30, 0x7F, 0x7F, 0x00 }, // U+0057 (W){ 0x43, 0x67, 0x3C, 0x18, 0x3C, 0x67, 0x43, 0x00 }, // U+0058 (X){ 0x07, 0x4F, 0x78, 0x78, 0x4F, 0x07, 0x00, 0x00 }, // U+0059 (Y){ 0x47, 0x63, 0x71, 0x59, 0x4D, 0x67, 0x73, 0x00 }, // U+005A (Z){ 0x00, 0x7F, 0x7F, 0x41, 0x41, 0x00, 0x00, 0x00 }, // U+005B ([){ 0x01, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00 }, // U+005C (\){ 0x00, 0x41, 0x41, 0x7F, 0x7F, 0x00, 0x00, 0x00 }, // U+005D (]){ 0x08, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x08, 0x00 }, // U+005E (^){ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }, // U+005F (_){ 0x00, 0x00, 0x03, 0x07, 0x04, 0x00, 0x00, 0x00 }, // U+0060 (`){ 0x20, 0x74, 0x54, 0x54, 0x3C, 0x78, 0x40, 0x00 }, // U+0061 (a){ 0x41, 0x7F, 0x3F, 0x48, 0x48, 0x78, 0x30, 0x00 }, // U+0062 (b){ 0x38, 0x7C, 0x44, 0x44, 0x6C, 0x28, 0x00, 0x00 }, // U+0063 (c){ 0x30, 0x78, 0x48, 0x49, 0x3F, 0x7F, 0x40, 0x00 }, // U+0064 (d){ 0x38, 0x7C, 0x54, 0x54, 0x5C, 0x18, 0x00, 0x00 }, // U+0065 (e){ 0x48, 0x7E, 0x7F, 0x49, 0x03, 0x02, 0x00, 0x00 }, // U+0066 (f){ 0x98, 0xBC, 0xA4, 0xA4, 0xF8, 0x7C, 0x04, 0x00 }, // U+0067 (g){ 0x41, 0x7F, 0x7F, 0x08, 0x04, 0x7C, 0x78, 0x00 }, // U+0068 (h){ 0x00, 0x44, 0x7D, 0x7D, 0x40, 0x00, 0x00, 0x00 }, // U+0069 (i){ 0x60, 0xE0, 0x80, 0x80, 0xFD, 0x7D, 0x00, 0x00 }, // U+006A (j){ 0x41, 0x7F, 0x7F, 0x10, 0x38, 0x6C, 0x44, 0x00 }, // U+006B (k){ 0x00, 0x41, 0x7F, 0x7F, 0x40, 0x00, 0x00, 0x00 }, // U+006C (l){ 0x7C, 0x7C, 0x18, 0x38, 0x1C, 0x7C, 0x78, 0x00 }, // U+006D (m){ 0x7C, 0x7C, 0x04, 0x04, 0x7C, 0x78, 0x00, 0x00 }, // U+006E (n){ 0x38, 0x7C, 0x44, 0x44, 0x7C, 0x38, 0x00, 0x00 }, // U+006F (o){ 0x84, 0xFC, 0xF8, 0xA4, 0x24, 0x3C, 0x18, 0x00 }, // U+0070 (p){ 0x18, 0x3C, 0x24, 0xA4, 0xF8, 0xFC, 0x84, 0x00 }, // U+0071 (q){ 0x44, 0x7C, 0x78, 0x4C, 0x04, 0x1C, 0x18, 0x00 }, // U+0072 (r){ 0x48, 0x5C, 0x54, 0x54, 0x74, 0x24, 0x00, 0x00 }, // U+0073 (s){ 0x00, 0x04, 0x3E, 0x7F, 0x44, 0x24, 0x00, 0x00 }, // U+0074 (t){ 0x3C, 0x7C, 0x40, 0x40, 0x3C, 0x7C, 0x40, 0x00 }, // U+0075 (u){ 0x1C, 0x3C, 0x60, 0x60, 0x3C, 0x1C, 0x00, 0x00 }, // U+0076 (v){ 0x3C, 0x7C, 0x70, 0x38, 0x70, 0x7C, 0x3C, 0x00 }, // U+0077 (w){ 0x44, 0x6C, 0x38, 0x10, 0x38, 0x6C, 0x44, 0x00 }, // U+0078 (x){ 0x9C, 0xBC, 0xA0, 0xA0, 0xFC, 0x7C, 0x00, 0x00 }, // U+0079 (y){ 0x4C, 0x64, 0x74, 0x5C, 0x4C, 0x64, 0x00, 0x00 }, // U+007A (z){ 0x08, 0x08, 0x3E, 0x77, 0x41, 0x41, 0x00, 0x00 }, // U+007B ({){ 0x00, 0x00, 0x00, 0x77, 0x77, 0x00, 0x00, 0x00 }, // U+007C (|){ 0x41, 0x41, 0x77, 0x3E, 0x08, 0x08, 0x00, 0x00 }, // U+007D (}){ 0x02, 0x03, 0x01, 0x03, 0x02, 0x03, 0x01, 0x00 }, // U+007E (~){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } // U+007F
};#endif /* MAIN_FONT8X8_BASIC_H_ */
3. i2c 操作示例 main.c
#include <string.h>#include "driver/gpio.h"
#include "driver/i2c.h"
#include "esp_err.h"
#include "esp_log.h"
#include "freertos/task.h"#include "sdkconfig.h" #include "oled/include/ssd1366.h"
#include "oled/include/font8x8_basic.h"#define SDA_PIN GPIO_NUM_4
#define SCL_PIN GPIO_NUM_5#define tag "SSD1306"void i2c_master_init() {i2c_config_t i2c_config = {.mode = I2C_MODE_MASTER,.sda_io_num = SDA_PIN,.scl_io_num = SCL_PIN,.sda_pullup_en = GPIO_PULLUP_ENABLE,.scl_pullup_en = GPIO_PULLUP_ENABLE,.master.clk_speed = 100000,.clk_flags = I2C_SCLK_SRC_FLAG_FOR_NOMAL};i2c_param_config(I2C_NUM_0, &i2c_config);i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0);
}void ssd1306_init() {esp_err_t espRc;i2c_cmd_handle_t cmd = i2c_cmd_link_create();// 向 I2C 总线发送启动信号,表示一个新的传输事务即将开始。i2c_master_start(cmd);// 写入一个字节到 I2C 总线。这里使用 OLED 模块的 I2C 地址,左移一位并加上写入标志,指示写入操作i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);// 写入 OLED 控制命令流的字节,表示后续的字节是控制命令。i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true);// 写入 OLED 控制命令,设置充电泵i2c_master_write_byte(cmd, OLED_CMD_SET_CHARGE_PUMP, true);// 写入参数字节i2c_master_write_byte(cmd, 0x14, true);// 写入 OLED 控制命令,设置段重映射,即左右反转i2c_master_write_byte(cmd, OLED_CMD_SET_SEGMENT_REMAP, true); // reverse left-right mapping// 写入 OLED 控制命令,设置行扫描模式,即上下反转i2c_master_write_byte(cmd, OLED_CMD_SET_COM_SCAN_MODE, true); // reverse up-bottom mapping// 写入 OLED 控制命令,打开 OLED 显示i2c_master_write_byte(cmd, OLED_CMD_DISPLAY_ON, true);// 向 I2C 总线发送停止信号,表示传输事务结束。i2c_master_stop(cmd);// 执行 I2C 命令序列,将前面构建的命令发送到 I2C 总线上。返回的 espRc 变量会保存执行结果。espRc = i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS);if (espRc == ESP_OK) {ESP_LOGI(tag, "OLED configured successfully");} else {ESP_LOGE(tag, "OLED configuration failed. code: 0x%.2X", espRc);}// 释放创建的 I2C 命令句柄,以便后续的使用i2c_cmd_link_delete(cmd);
}void task_ssd1306_display_text(void *arg_text) {char *text = (char *)arg_text;uint8_t text_len = strlen(text);i2c_cmd_handle_t cmd;uint8_t cur_page = 0;// 重置起始位置cmd = i2c_cmd_link_create();i2c_master_start(cmd);i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true);i2c_master_write_byte(cmd, 0x00, true); // reset columni2c_master_write_byte(cmd, 0x10, true);i2c_master_write_byte(cmd, 0xB0 | cur_page, true); // reset pagei2c_master_stop(cmd);i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS);i2c_cmd_link_delete(cmd);for (uint8_t i = 0; i < text_len; i++) {if (text[i] == '\n') {// 换行cur_page++;if (cur_page >= 8) {break; // 显示完整文本,超出屏幕范围,退出}cmd = i2c_cmd_link_create();i2c_master_start(cmd);i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true);i2c_master_write_byte(cmd, 0x00, true); // reset columni2c_master_write_byte(cmd, 0x10, true);i2c_master_write_byte(cmd, 0xB0 | cur_page, true); // increment pagei2c_master_stop(cmd);i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS);i2c_cmd_link_delete(cmd);} else {// 显示字符cmd = i2c_cmd_link_create();i2c_master_start(cmd);i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_DATA_STREAM, true);i2c_master_write(cmd, font8x8_basic_tr[(uint8_t)text[i]], 8, true);i2c_master_stop(cmd);i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS);i2c_cmd_link_delete(cmd);}}vTaskDelete(NULL);
}
void generate_string(int columns, int newlines, char* ret) {char buffer[columns*newlines+1];int j=0;for(int page=0;page<newlines;page++){for(int i=0;i<columns;i++){buffer[j] = ' ';j++;}buffer[j]='\n';j++;}buffer[j] = '\0';strcpy(ret, buffer);
}void app_main(void) {i2c_master_init();ssd1306_init();// 清屏操作const int columns = 16;const int page = 8;char space[columns*page+1];generate_string(columns, page, space);// 清除屏幕内容xTaskCreate(&task_ssd1306_display_text, "ssd1306_display_text", 2048, (void *)space, 6, NULL);// 间隔一会防止进程有干扰vTaskDelay(500/portTICK_PERIOD_MS);xTaskCreate(&task_ssd1306_display_text, "ssd1306_display_text", 2048,(void *) "Hello world!\nMulitine is OK!\nAnother line", 6, NULL);while(1){vTaskDelay(1);}
}
四、Espressif 官方的 ssd1306驱动使用方法
1. 使用idf.py命令加载库
idf.py add-dependency "espressif/ssd1306^1.0.5"
2. 下载源码加入工程
需要适当修改引用头的路径
3. main.c 实例
#include <stdio.h>
#include "oled/include/ssd1306.h"
#include <math.h>#define I2C_MASTER_SCL_IO 5
#define I2C_MASTER_SDA_IO 4
#define I2C_MASTER_NUM I2C_NUM_0
#define I2C_MASTER_FREQ_HZ 100000static ssd1306_handle_t ssd1306_dev = NULL;void draw_circle(int center_x, int center_y, int radius, uint8_t color) {for (int i = 0; i < 360; i++) {float angle = i * M_PI / 180.0;int x = center_x + radius * cos(angle);int y = center_y + radius * sin(angle);ssd1306_fill_point(ssd1306_dev, x, y, color);}
}void draw_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint8_t color) {ssd1306_draw_line(ssd1306_dev, x0, y0, x1, y1);ssd1306_draw_line(ssd1306_dev, x1, y1, x2, y2);ssd1306_draw_line(ssd1306_dev, x2, y2, x0, y0);
}void app_main(void)
{i2c_config_t conf;conf.mode = I2C_MODE_MASTER;conf.sda_io_num = (gpio_num_t)I2C_MASTER_SDA_IO;conf.sda_pullup_en = GPIO_PULLUP_ENABLE;conf.scl_io_num = (gpio_num_t)I2C_MASTER_SCL_IO;conf.scl_pullup_en = GPIO_PULLUP_ENABLE;conf.master.clk_speed = I2C_MASTER_FREQ_HZ;conf.clk_flags = I2C_SCLK_SRC_FLAG_FOR_NOMAL;i2c_param_config(I2C_MASTER_NUM, &conf);i2c_driver_install(I2C_MASTER_NUM, conf.mode, 0, 0, 0);ssd1306_dev = ssd1306_create(I2C_MASTER_NUM, SSD1306_I2C_ADDRESS);ssd1306_init(ssd1306_dev);ssd1306_clear_screen(ssd1306_dev, 0x00);char data_str[10] = {0};sprintf(data_str, "C STR");ssd1306_draw_string(ssd1306_dev, 70, 16, (const uint8_t *)data_str, 16, 1);// 绘制圆draw_circle(30, 40, 20, 1);// 绘制三角形draw_triangle(80, 10, 100, 40, 60, 50, 1);ssd1306_refresh_gram(ssd1306_dev);
}
运行效果: