ESP32 -IIC2显示OLED 屏幕
一、ESP32 IIC介绍:
ESP32 有 2 个 I2C 总线接口,根据用户的配置,总线接口可以用作 I2C 主机或从机模式。 I2C 接口支持:
• 标准模式 (100 Kbit/s)
• 高速模式 (400 Kbit/s)
• 速度最高可达 5 MHz,但受制于 SDA 上拉强度
• 7-bit/10-bit 寻址模式
• 双寻址模式
用户可以配置指令寄存器来控制 I2C 接口,从而实现更多灵活的应用。
二、I2C 简介
I2C 是一个两线总线,由 SDA 线和 SCL 线构成。这些线设置为漏极开漏输出。因此, I2C 总线上可以挂载多个外设,通常是和一个或多个主机以及一个或多个从机。主机通过总线访问从机。
①:主机发出开始信号,则通讯开始:在 SCL 为高电平时拉低 SDA 线,主机将通过 SCL 线发出 9 个时钟脉冲。前8 个脉冲用于按位传输,该字节包括 7-bit 地址和 1 个读写位。
②:如果从机地址与该 7-bit 地址一致,那么从机可以通过在第 9 个脉冲上拉低 SDA 线来应答。
③:接下来,根据读/写标志位,主机和从机可以发送/接收更多的数据。
④:根据应答位的逻辑电平决定是否停止发送数据。
⑤:在数据传输中, SDA 线仅在 SCL 线为低电平时才发生变化。当主机完成通讯,回发送一个停止标志:在 SCL 为高电平时,拉高 SDA 线。
ESP32 I2C 控制器可以处理 I2C 协议,腾出处理器核用于其它任务。
三、SSD1306-I2C-通道2 显示OLED 屏幕
使用SSD1306库的时候默认使用iic通道一,但是这个可以在初始化的时候更改。
初始化的时候我们定义了一个SSD1306Wire 类型的类。
// Initialize the OLED display using Wire library
SSD1306Wire display(0x3c, SDA, SCL);
右键查看定义:或者是按F12查看定义
此时应该会出现这个类,往下翻。
其中有一个选项就是设置iic总线通道,根据注释,如果设置为I2C_ONE 就是选择通道一,如果设置为I2C_TWO的话就是选择通道二,默认选择通道一。
同时可以看出下方根据设置的I2C_ONE 和I2C_TWO来选择 Wire 和Wire1
但是这个也有一个缺点,我感觉如果你想用这个SSD1306库的话,不能同时选择i2c的通道二和通道一,只能选择一个。
但是我觉得这个初始化的时候,后边赋值的参数可以增加I2C_ONE 和I2C_TWO,我尝试了一番发现会报错,应该是我技术不太行。反正这个涉及到一些宏定义,如果有朋友精通的话欢迎留言。
SSD1306Wire display(0x3c, SDA, SCL,I2C_TWO);
这在里顺边附上显示程序的代码:
#include <Arduino.h>
// Include the correct display library
// For a connection via I2C using Wire include
#include <Wire.h> // Only needed for Arduino 1.6.5 and earlier
#include "SSD1306Wire.h" // legacy include: `#include "SSD1306.h"`
// Initialize the OLED display using Wire library
SSD1306Wire display(0x3c, SDA, SCL);
void setup() {
Serial.begin(115200);
// Initialising the UI will init the display too.
display.init();
// This will make sure that multiple instances of a display driver
// running on different ports will work together transparently
display.setI2cAutoInit(true);
display.flipScreenVertically();
display.setFont(ArialMT_Plain_16);
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.clear();
display.drawString(0, 0, "Hello world ");
display.drawString(0, 15, "Hello world ");
display.drawString(0, 30, "Hello world ");
display.display();
}
void loop() {
}
具体关于这个库SSD1306的使用参考这篇文章链接: 玩转 ESP32 + Arduino (二十五) SSD1306库驱动OLED
四、U8G2-I2C-通道2 显示OLED 屏幕
在u8g2库初始化的时候有好多,会有好多宏定义比如最常用的是:U8G2_SSD1306_128X64_VCOMH0_1_HW_I2C
如果想选择iic的第二通道的话,右键选择查看定义,或者是手动打开u8g2lib.h文件,
里边有好多初始化的类,选择带有_2ND_的类,在初始化的过程中会调用u8x8_byte_arduino_hw_i2c,继而选择iic的第二通道。
这里我们注意到:
其中iic的通道二在初始化的时候,不能选择scl的sda,只能选择默认,我们通过右键查看u8x8_SetPin_HW_I2C(getU8x8(), reset);的定义
class U8G2_SSD1306_128X64_NONAME_1_2ND_HW_I2C : public U8G2 {
public: U8G2_SSD1306_128X64_NONAME_1_2ND_HW_I2C(const u8g2_cb_t *rotation, uint8_t reset = U8X8_PIN_NONE) : U8G2() {
u8g2_Setup_ssd1306_i2c_128x64_noname_1(&u8g2, rotation, u8x8_byte_arduino_2nd_hw_i2c, u8x8_gpio_and_delay_arduino);
u8x8_SetPin_HW_I2C(getU8x8(), reset);
}
};
但是在这里,你要是不传入clock和data的话,怎么能确实引脚呢,值得思考。
void u8x8_SetPin_HW_I2C(u8x8_t *u8x8, uint8_t reset, uint8_t clock, uint8_t data)
{
u8x8_SetPin(u8x8, U8X8_PIN_RESET, reset);
u8x8_SetPin(u8x8, U8X8_PIN_I2C_CLOCK, clock);
u8x8_SetPin(u8x8, U8X8_PIN_I2C_DATA, data);
}
#define U8X8_PIN_I2C_CLOCK 12 /* 1 = Input/high impedance, 0 = drive low */
#define U8X8_PIN_I2C_DATA 13 /* 1 = Input/high impedance, 0 = drive low */
我用通道二写的时候,发现可以编译下载,但是我不知道使用的是那个引脚。
这里就各位朋友自己尝试叭
U8G2_SSD1306_128X64_NONAME_1_2ND_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
下面附上一个OLED 屏幕的代码,使用的通道一编写的
#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>
//U8G2_SSD1306_128X64_NONAME_1_2ND_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE, /* clock=*/22, /* data=*/21);
void setup(void) {
u8g2.begin();
u8g2.enableUTF8Print(); // enable UTF8 support for the Arduino print() function
u8g2.setFont(u8g2_font_unifont_t_chinese2); // use chinese2 for all the glyphs of "你好世界"
}
void loop(void) {
u8g2.setFontDirection(0);
u8g2.firstPage();
do {
u8g2.setCursor(0, 15);
u8g2.print("Hello World");
u8g2.setCursor(0, 40);
u8g2.print("你好世界"); // Chinese "Hello World"
} while ( u8g2.nextPage() );
}
具体关于这个库U8G2的使用参考这篇文章链接: 玩转 ESP32 + Arduino (八) U8G2驱动OLED
五、总结
如果一个项目使用多个OLED 屏幕的话,理论上可以全部挂在一条总线上的,他们相互之间是通过地址辨别的,这里只是提供一种使用iic2的思路。
更多推荐