ESP32的所有GPIO都可以配置为硬件I2C接口,这一点很方便。这里使用ESP32的I2C接口来驱动一个OLED,来验证I2C接口的用法。
一、新建工程
参照前面ESP32点亮LED的方法,以“hello_world”工程为模板,创建一个新的工程。新工程命名为:i2c_oled01,如下图所示:
二、添加OLED驱动文件
我之前在STM32和ESP8266中驱动过OLED屏幕,把相关的源文件拷贝到main文件夹下面。如下图:
返回到vs code中,可以看到该文件夹已经刷新到了main路径下:
三、修改cmakelists.txt文件
只是把源文件放进去还不行,还要让这个工程知道你添加了这个文件夹。双击main下面的cmakelists.txt文件,注意不是工程根目录下的cmakelists.txt文件。
如图所示,右侧内容如下:
idf_component_register(SRCS "hello_world_main.c"
INCLUDE_DIRS "")
需要添加文件路径和c文件名,修改后如下:
上面添加了:oled/user_oled.c,即C源文件。
第二行添加了:”oled”,即文件路径。
修改后保存。我始终搞不懂,一个单片机级别的东西,搞这么复杂,肯定是哪里不正常!
四、I2C接口初始化
这部分内容较多,包括头文件、相关接口定义、I2C初始化等。依次如下:
4.1 添加ESP32的I2C头文件
双击打开“user_oled.c”文件,添加ESP32的I2C头文件:
esp_system.h,包含一些基本参数;
driver/i2c_master.h,包含I2C接口相关的函数。
4.2 I2C接口初始化
你想把哪些管脚定义为I2C,在这里操作,如下:
#define SCL_IO_PIN 23
#define SDA_IO_PIN 22
#define MASTER_FREQUENCY 100000
#define PORT_NUMBER 0
static i2c_master_bus_handle_t bus_handle;
static i2c_master_dev_handle_t dev_handle;
void esp32_i2c_init(void)
{
i2c_master_bus_config_t i2c_bus_config = {
.clk_source = I2C_CLK_SRC_DEFAULT, //CLK时钟源
.i2c_port = PORT_NUMBER,
.scl_io_num = SCL_IO_PIN,
.sda_io_num = SDA_IO_PIN,
.glitch_ignore_cnt = 7, //滤波参数,默认7即可
.flags.enable_internal_pullup = 0, //I2C的上拉电阻。0,禁止;1,使能
};
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_config, &bus_handle));
i2c_device_config_t dev_cfg = {0};
dev_cfg.dev_addr_length = I2C_ADDR_BIT_LEN_7; // 7位地址
dev_cfg.device_address = 0x3c;
dev_cfg.scl_speed_hz = MASTER_FREQUENCY; // 100kHz
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
}
如上,IO22定义为SDA,IO23定义为SCL。通信频率定义为100KHZ,端口号PORT_NUMBER一般0~1都行。
static i2c_master_bus_handle_t bus_handle;
static i2c_master_dev_handle_t dev_handle;
这里定义了两个句柄,一个是主机总线句柄,用来配置I2C总线相关参数;另一个是主机设备句柄,用来设置I2C主机下设备的相关参数。代码写的很清晰,直接看即可。
五、I2C写操作函数编写
编写一个函数,可以用来给OLED写入数据或命令。如下:
void i2c_example_master_oled_write(uint8_t reg_address, uint8_t *data, size_t data_len)
{
uint8_t dat_buf[2] = {0};
dat_buf[0] = reg_address;
dat_buf[1] = *data;
ESP_ERROR_CHECK(i2c_master_transmit(dev_handle, dat_buf, 2, -1));
}
该函数有三个参数,第一个reg_address,即你要对OLED的哪个寄存器或哪个地址操作;第二个参数,你要写入的数据的地址;第三个参数,数据长度,但是没用到。
这里可以看到,向I2C设备进行写操作时,是不需要写手动写入器件地址的。因为前面配置主机设备句柄时,已经写好了。
六、编译、下载
把I2C初始化和OLED配置的代码放到主函数里,如下:
都改完了,编译、烧录即可。 如果编译时有报错,可以尝试删除之前的构建信息,然后重新编译。
能看到OLED屏幕显示:
最后,需要注意的一个地方就是,设置I2C设备的器件地址时,格式为7位地址格式。而我的OLED屏幕上,备注了器件地址为0x78,如下图:
这个地址,看不出到底是7位的格式还是8位的格式,只能挨个试一下。像我这里,它其实是8位的格式,7位地址的话应该是0x3c。各位用的时候注意即可。
我是单片机爱好者-MCU起航,打完收工!