ESP-C3入门21. I2C接口点亮1306驱动的OLED屏

news2024/11/16 22:01:44

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 库的一些主要特点和功能:

  1. OLED 控制:该库允许你控制 SSD1306 驱动的 OLED 显示屏,包括初始化、绘制图像、显示文本等。
  2. 支持 I2C 和 SPI 接口:该库支持使用 I2C 和 SPI 接口来与 OLED 显示屏通信。你可以根据你的项目需要选择适当的接口。
  3. 支持多种显示模式:Espressif/ssd1306 库支持多种显示模式,如水平、垂直滚动、反显等。
  4. 使用 C 语言:该库是用 C 语言编写的,与 ESP-IDF 框架相匹配,可在 ESP32 和 ESP8266 上使用。
  5. 开源: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_tr
   Contains an 90 digree transposed 8x8 font map for unicode points
   U+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.h

   Conversion 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 column
    i2c_master_write_byte(cmd, 0x10, true);
    i2c_master_write_byte(cmd, 0xB0 | cur_page, true); // reset page
    i2c_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 column
            i2c_master_write_byte(cmd, 0x10, true);
            i2c_master_write_byte(cmd, 0xB0 | cur_page, true); // increment page
            i2c_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 100000

static 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);
}

运行效果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/890357.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

异步更新队列 - Vue2 响应式

前言 这篇文章分析了 Vue 更新过程中使用的异步更新队列的相关代码。通过对异步更新队列的研究和学习&#xff0c;加深对 Vue 更新机制的理解 什么是异步更新队列 先看看下面的例子&#xff1a; <div id"app"><div id"div" v-if"isShow&…

有哪些好用的设计图工具?

设计图纸制作软件是高级学习数字设计的最佳选择&#xff0c;无论你是想通过设计图纸制作软件创建一个明亮的设计&#xff0c;还是与其他设计师分享和交流。本文将介绍十个易于使用的设计图纸制作软件&#xff0c;其中大多数是初学者和高级艺术家&#xff0c;具有完整的绘图、照…

科研论文配图绘制指南——基于Python—第一章

目录 第一章1.1科研论文配图的绘制基础1.2科研论文配图的配色基础1.2.1 色轮配色原理1.2.3 颜色主题1.2.4 配色工具 总结 第一章 1.1科研论文配图的绘制基础 科研配图包括线性图、灰度图、照片彩图和综合配图四种类型&#xff0c;最经常使用为线型图。 建议使用EPS、PDF等矢量…

C语言:每日一练(选择+编程)

目录 选择题&#xff1a; 题一&#xff1a; 题二&#xff1a; 题三&#xff1a; 题四&#xff1a; 题五&#xff1a; 编程题&#xff1a; 题一&#xff1a;打印1到最大的n位数 示例1 思路一&#xff1a; 题二&#xff1a;计算日期到天数转换 示例1 思路一&#xf…

SwiftUI 动画进阶:实现行星绕圆周轨道运动

0. 概览 SwiftUI 动画对于优秀 App 可以说是布帛菽粟。利用美妙的动画我们不仅可以活跃界面元素,更可以单独打造出一整套生动有机的世界,激活无限可能。 如上图所示,我们用动画粗略实现了一个小太阳系:8大行星围绕太阳旋转,而卫星们围绕各个行星旋转。 在本篇博文中,您将…

华为网络篇 RIP路由标记-31

难度2复杂度2 目录 一、实验原理 二、实验拓扑 三、实验步骤 四、实验过程 总结 一、实验原理 路由标记tag是用于进行路由过滤的&#xff0c;它给相关的路由打标记&#xff0c;然后应用于路由策略中&#xff0c;路由器会根据策略进行路由过滤。比如&#xff0c;给静态路由…

题目:售货员的难题(状压dp)

售货员的难题 题目描述输入输出格式输入格式&#xff1a;输出格式&#xff1a; 输入输出样例输入样例#1&#xff1a;输出样例#1&#xff1a; 思路AC代码&#xff1a; 题目描述 某乡有n个村庄( 1 < n < 16 )&#xff0c;有一个售货员&#xff0c;他要到各个村庄去售货&am…

Smartbi 李代:人尽其才、数尽其用,Smartbi Eagle智慧数据运营平台全新亮相

数据是企业数字化转型的基石&#xff0c;也是赢得未来的核心资产和竞争力。数字化转型的关键&#xff0c;是在全公司建立一种数据驱动的组织和机制&#xff0c;营造数据文化的氛围&#xff0c;让更多的用户、在更多的场景中&#xff0c;有意愿、有能力使用数据&#xff0c;从而…

【C++】面向对象编程引入 ③ ( 面向过程编程的结构化程序设计方法 | 结构化程序设计方法概念 / 特点 / 优缺点 | 面向对象编程引入 )

文章目录 一、面向过程编程的结构化程序设计方法1、结构化程序设计方法概念2、结构化程序设计方法特点3、结构化程序设计方法优缺点 二、面向对象编程引入 一、面向过程编程的结构化程序设计方法 如果使用 面向过程语言 ( 如 : C 语言 ) , 开发 大型 项目 , 一般使用 结构化程序…

Apache SeaTunnel社区迎来新Committer!

采访&编辑 | Debra Chen 个人简介 姓名&#xff1a;马骋原公司&#xff1a;恒生电子 GitHub ID&#xff1a;rewerma个人擅长研究领域&#xff1a;java中间件、微服务、大数据等 您为社区提交了什么贡献&#xff1f;具体方案可以描述一下吗&#xff1f; 为SeatTunnel提交…

案例21 基于Spring Boot+Redis实现图书信息按书号存储案例

1. 案例需求 基于Spring BootRedis实现图书信息按书号存储和取出功能&#xff0c;数据存储至Redis。 2. 创建Spring Boot项目 创建Spring Boot项目&#xff0c;项目名称为springboot-redis02。 3. 选择依赖 ​ pom.xml文件内容如下所示&#xff1a; <?xml version&quo…

入门Web自动化测试之元素定位的配置管理

之前我们讲过Selenium使用教程&#xff0c;这一篇我们来学习元素定位的配置管理。 目的 Web自动化测试作为软件自动化测试领域中绕不过去的一个“香饽饽”&#xff0c;通常都会作为广大测试从业者的首选学习对象&#xff0c;相较于C/S架构的自动化来说&#xff0c;B/S有着其无…

AI巨浪下,数据技术如何驱动智能未来?

引言 数据技术是大数据时代的核心驱动力&#xff0c;也是推动各行各业数字化转型和智能化升级的关键因素。随着云计算、人工智能、区块链等新兴技术的不断发展和融合&#xff0c;数据技术也呈现出多模态、混合处理、自动化管理等新的趋势和特点。 8 月 19 日&#xff08;周六&…

UniApp 制作高德地图插件

1、下载Uni插件项目 在Uni官网下载Uni插件项目&#xff0c;并参考官网插件项目创建插件项目. 开发者须知 | uni小程序SDK 如果下载下来项目运行不了可以参考下面链接进行处理 UniApp原生插件制作_wangdaoyin2010的博客-CSDN博客 2、引入高德SDK 2.1 在高德官网下载对应SD…

e6zzseo:跨境独立站还能做起来吗?

跨境独立站指的是在其他国家或地区创建和运营自己的电子商务网站。虽然跨境独立站在理论上是可行的&#xff0c;但成功实施和运营它可能面临一些挑战。以下是e6zzseo分析的一些考虑因素和建议&#xff0c;以帮助你更好地评估是否可以成功运营跨境独立站&#xff1a; 做跨境独立…

【0基础入门Python笔记】python 之基础语法、基础数据类型、复合数据类型及基本操作

python 基础&#xff08;一&#xff09; 基础语法规则基础数据类型数字类型&#xff08;Numbers&#xff09;字符串类型&#xff08;String&#xff09;布尔类型&#xff08;Boolean&#xff09; 复合数据类型List&#xff08;列表&#xff09;Tuple&#xff08;元组&#xff0…

excel常见的数学函数篇2

二、数学函数 1、ABS(number)&#xff1a;返回数字的绝对值 语法&#xff1a;ABS(数字)&#xff1b;返回数字的绝对值&#xff1b;若引用单元格&#xff0c;把数字换为单元格地址即可 2、INT(number)&#xff1a;向小取整 语法&#xff1a;INT(数字)&#xff1b;若引用单元格…

自夹持P型屏蔽型碳化硅沟槽型绝缘栅双极晶体管,用于低开通电压和开关损耗

目录 标题&#xff1a;Self-Clamped P-shield SiC Trench IGBT for Low On-State Voltage and Switching LossProceedings of the 35st International Symposium on Power Semiconductor Devices & ICs摘要信息解释研究了什么文章的创新点文章的研究方法文章的结论 标题&am…

为什么要报11月份的PMP考试?一篇说清楚!

各位PMP考生即将迎来8.19的考试&#xff0c;现在心里难免会有点焦虑&#xff0c;相信大家在系统的学习完PMP课程之后&#xff0c;都能顺利上岸&#xff0c;3A通过&#xff01; 另外PMP11月份的考试正在报名当中&#xff01;大家尽量提前报名&#xff0c;给自己留充足的时间备考…

夏威夷等全球多地深陷「末日狂烧」,关键时刻 AI 监测能否跑赢野火?

内容一览&#xff1a;当地时间 8 月 8 日&#xff0c;美国夏威夷州突发野火&#xff0c;当地居民和游客不得不跳入太平洋中躲避火势。截至 8 月 17 日&#xff0c;这场野火已经造成110 人死亡&#xff0c;超过 1000人失踪。与此同时&#xff0c;美国、加拿大、法国等地也正遭遇…