I2C通信协议
I2C协议简介
I2C(Inter-Integrated Circuit)是一种串行通信协议,用于在微控制器和其他数字设备之间进行通信。I2C协议支持多主多从通信,允许多个设备通过一条数据线(SDA)和一条时钟线(SCL)进行通信。
1. I2C协议特点
- 多主多从:I2C协议支持多主多从通信,允许多个主设备和一个或多个从设备同时进行通信。
- 串行通信:I2C协议采用串行通信方式,数据在SDA线上按位传输。
- 半双工:I2C协议是半双工通信,即每个设备只能在发送或接收数据时使用SDA和SCL。
- 低功耗:I2C协议具有低功耗特性,适用于低功耗应用。
- 简单:I2C协议简单易用,易于实现和调试。
2. I2C协议工作原理
I2C协议的工作原理如下:
- 起始信号:当主设备需要与从设备通信时,它会发送一个起始信号。起始信号由主设备在SCL线上拉低,然后在SDA线上拉高。
- 地址信号:主设备发送从设备的地址,地址由7位(包括读写位)或是 10位(包括读写位) 组成。主设备发送地址后,从设备会根据地址判断是否响应。
- 数据传输:主设备发送数据或从设备发送数据。数据在SDA线上按位传输,每个位在SCL线上的上升沿或下降沿采样。
- 应答信号:从设备在接收完数据后,会发送一个应答信号。应答信号由从设备在SCL线上拉低,然后在SDA线上拉高。
- 停止信号:当主设备完成数据传输后,它会发送一个停止信号。停止信号由主设备在SCL线上拉低,然后在SDA线上拉高。
I2C协议的程序实现
- 创建一个 Bus 总线 :
i2c_new_master_bus
生成一个bus_handle
- 添加一个设备 :
i2c_master_bus_add_device
生成一个dev_handle
- 读写数据 :
i2c_master_transmit_receive
I2C协议的程序代码
1. 创建一个 Bus 总线
c
#include "driver/i2c_master.h"
i2c_master_bus_config_t i2c_mst_config = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.i2c_port = TEST_I2C_PORT,
.scl_io_num = I2C_MASTER_SCL_IO,
.sda_io_num = I2C_MASTER_SDA_IO,
.glitch_ignore_cnt = 7,
.flags.enable_internal_pullup = true,
};
i2c_master_bus_handle_t bus_handle;
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));
i2c_device_config_t dev_cfg = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = 0x58,
.scl_speed_hz = 100000,
};
i2c_master_dev_handle_t dev_handle;
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
2. 主机只写入数据
c
i2c_master_transmit(dev_handle, data_wr, DATA_LENGTH, -1)
I2C 主机写入操作还支持在单次传输事务中传输多个 buffer
c
i2c_master_transmit_multi_buffer_info_t lcd_i2c_buffer[3] = {
{.write_buffer = &control_phase_byte, .buffer_size = control_phase_size},
{.write_buffer = cmd_buffer, .buffer_size = cmd_buffer_size},
{.write_buffer = lcd_buffer, .buffer_size = lcd_buffer_size},
};
i2c_master_multi_buffer_transmit(handle, lcd_i2c_buffer, sizeof(lcd_i2c_buffer) / sizeof(i2c_master_transmit_multi_buffer_info_t), -1);
2. 主机只读取数据
c
i2c_master_receive(dev_handle, data_rd, DATA_LENGTH, -1);
2. 写入命令并返回读取数据
c
i2c_master_transmit_receive(dev_handle, 0x58, &write_data, 1, &read_data, 1, 1000 / portTICK_PERIOD_MS);