【esp32 idf入门】快速使用i2c发送和接收数据


前言

ESP32 是一款集成了 Wi-Fi 和 Bluetooth 的高性能低功耗系统级芯片(SoC),广泛应用于物联网 (IoT) 领域。ESP32 支持多种通信协议,其中 I2C(Inter-Integrated Circuit)是一种常用的串行通信协议,用于连接微控制器与外围设备。本文将介绍如何快速在 ESP32 上使用 I2C 协议发送和接收数据,帮助初学者快速上手 ESP-IDF(Espressif IoT Development Framework)。


观前须知

上篇I2C文章I2C他的代码也是OK没有问题的,那为什么有这篇文章呢?
原因就是上篇文章的操作方法太过复杂了,还需要什么开始命令这些,非常恶心,idf提供了类似于STM32的Mem模式,使用一个函数即可发送指令读取指定位置的数据

函数介绍

i2c_master_write_read_device

函数原型
esp_err_t i2c_master_write_read_device(
    i2c_port_t i2c_num,
    uint8_t device_address,
    const uint8_t *write_buffer,
    size_t write_size,
    uint8_t *read_buffer,
    size_t read_size,
    TickType_t ticks_to_wait
);
函数作用

该函数用于在 I2C 主设备上执行写操作和读操作,通常用于先发送命令或地址,然后读取从设备的响应数据。它将写入和读取操作结合在一次传输中,减少了通信开销。

参数介绍
  • i2c_port_t i2c_num: I2C 端口号,取值为 I2C_NUM_0I2C_NUM_1,表示使用的 I2C 控制器。
  • uint8_t device_address: I2C 从设备的 7 位地址。
  • const uint8_t *write_buffer: 指向要写入的数据缓冲区的指针。
  • size_t write_size: 要写入的数据字节数。
  • uint8_t *read_buffer: 指向用于存储读取数据的缓冲区的指针。
  • size_t read_size: 要读取的数据字节数。
  • TickType_t ticks_to_wait: 等待完成操作的最大时间,单位是系统时钟节拍数。
返回值
  • ESP_OK: 操作成功。
  • 其他 esp_err_t 错误代码: 操作失败,具体错误码可以帮助诊断问题。

i2c_master_write_to_device

函数原型
esp_err_t i2c_master_write_to_device(
    i2c_port_t i2c_num,
    uint8_t device_address,
    const uint8_t *write_buffer,
    size_t write_size,
    TickType_t ticks_to_wait
);
函数作用

该函数用于在 I2C 主设备上执行写操作,将指定的数据发送到 I2C 从设备。通常用于发送命令、寄存器地址或数据给从设备。

参数介绍
  • i2c_port_t i2c_num: I2C 端口号,取值为 I2C_NUM_0I2C_NUM_1,表示使用的 I2C 控制器。
  • uint8_t device_address: I2C 从设备的 7 位地址。
  • const uint8_t *write_buffer: 指向要写入的数据缓冲区的指针。
  • size_t write_size: 要写入的数据字节数。
  • TickType_t ticks_to_wait: 等待完成操作的最大时间,单位是系统时钟节拍数。
返回值
  • ESP_OK: 操作成功。
  • 其他 esp_err_t 错误代码: 操作失败,具体错误码可以帮助诊断问题。

示例

如果想要更多的示例,请找到你的idf安装目录,找到framework,找到esp-idf-v5.2.2,然后找到examples即可

使用 i2c_master_write_read_device 的示例

假设我们要从 I2C 从设备读取数据前,先发送一个命令:

#include <stdio.h>
#include "driver/i2c.h"

#define I2C_MASTER_SCL_IO 22           // I2C master clock pin
#define I2C_MASTER_SDA_IO 21           // I2C master data pin
#define I2C_MASTER_NUM I2C_NUM_0       // I2C port number
#define I2C_MASTER_FREQ_HZ 100000      // I2C master clock frequency
#define I2C_MASTER_TX_BUF_DISABLE 0    // I2C master doesn't need buffer
#define I2C_MASTER_RX_BUF_DISABLE 0    // I2C master doesn't need buffer
#define I2C_MASTER_TIMEOUT_MS 1000

#define DEVICE_ADDRESS 0x28            // I2C device address
#define WRITE_CMD 0x01                 // Command to be sent to the device

void app_main(void) {
    // Initialize I2C master
    i2c_config_t conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = I2C_MASTER_SDA_IO,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_io_num = I2C_MASTER_SCL_IO,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = I2C_MASTER_FREQ_HZ,
    };
    i2c_param_config(I2C_MASTER_NUM, &conf);
    i2c_driver_install(I2C_MASTER_NUM, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);

    uint8_t write_buffer = WRITE_CMD;
    uint8_t read_buffer[10];  // Buffer to store the read data

    esp_err_t ret = i2c_master_write_read_device(
        I2C_MASTER_NUM,
        DEVICE_ADDRESS,
        &write_buffer,
        sizeof(write_buffer),
        read_buffer,
        sizeof(read_buffer),
        pdMS_TO_TICKS(I2C_MASTER_TIMEOUT_MS)
    );

    if (ret == ESP_OK) {
        printf("Data read from device: ");
        for (int i = 0; i < sizeof(read_buffer); i++) {
            printf("%02x ", read_buffer[i]);
        }
        printf("\n");
    } else {
        printf("I2C read failed\n");
    }

    // Clean up
    i2c_driver_delete(I2C_MASTER_NUM);
}
使用 i2c_master_write_to_device 的示例

假设我们要将一些数据发送到 I2C 从设备:

#include <stdio.h>
#include "driver/i2c.h"

#define I2C_MASTER_SCL_IO 22           // I2C master clock pin
#define I2C_MASTER_SDA_IO 21           // I2C master data pin
#define I2C_MASTER_NUM I2C_NUM_0       // I2C port number
#define I2C_MASTER_FREQ_HZ 100000      // I2C master clock frequency
#define I2C_MASTER_TX_BUF_DISABLE 0    // I2C master doesn't need buffer
#define I2C_MASTER_RX_BUF_DISABLE 0    // I2C master doesn't need buffer
#define I2C_MASTER_TIMEOUT_MS 1000

#define DEVICE_ADDRESS 0x28            // I2C device address

void app_main(void) {
    // Initialize I2C master
    i2c_config_t conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = I2C_MASTER_SDA_IO,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_io_num = I2C_MASTER_SCL_IO,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = I2C_MASTER_FREQ_HZ,
    };
    i2c_param_config(I2C_MASTER_NUM, &conf);
    i2c_driver_install(I2C_MASTER_NUM, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);

    uint8_t write_buffer[] = {0x01, 0x02, 0x03, 0x04};  // Data to be sent to the device

    esp_err_t ret = i2c_master_write_to_device(
        I2C_MASTER_NUM,
        DEVICE_ADDRESS,
        write_buffer,
        sizeof(write_buffer),
        pdMS_TO_TICKS(I2C_MASTER_TIMEOUT_MS)
    );

    if (ret == ESP_OK) {
        printf("Data written to device successfully\n");
    } else {
        printf("I2C write failed\n");
    }

    // Clean up
    i2c_driver_delete(I2C_MASTER_NUM);
}

总结

通过本文的介绍,我们了解了如何在 ESP32 上使用 ESP-IDF 进行 I2C 通信,包括设置 I2C 配置、初始化 I2C 驱动程序、发送数据和接收数据。I2C 协议的简洁性和高效性,使其成为与传感器、显示屏等外设通信的理想选择。掌握了这些基础操作后,您可以根据实际需求扩展和应用 I2C 通信,为各种 IoT 项目开发奠定坚实的基础。

  • 12
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在 ESP-IDF 中,可以使用 uart_write_bytes() 函数发送 16 进制数据,使用 uart_read_bytes() 函数接收 16 进制数据。 例如,以下代码片段演示了如何发送和接收 16 进制数据: ```c // 设置串口参数 uart_config_t uart_config = { .baud_rate = 115200, .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE }; // 初始化串口 uart_param_config(UART_NUM_0, &uart_config); uart_set_pin(UART_NUM_0, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); uart_driver_install(UART_NUM_0, 1024, 0, 0, NULL, 0); // 发送 16 进制数据 uint8_t data[] = {0x12, 0x34, 0xAB, 0xCD}; uart_write_bytes(UART_NUM_0, (const char*)data, sizeof(data)); // 接收 16 进制数据 uint8_t rx_buffer[4]; uart_read_bytes(UART_NUM_0, rx_buffer, sizeof(rx_buffer), portMAX_DELAY); ``` 在以上代码中,我们首先使用 uart_param_config() 函数设置串口参数,然后使用 uart_set_pin() 函数将串口引脚设置为默认值,最后使用 uart_driver_install() 函数初始化串口。 接着,我们使用 uart_write_bytes() 函数发送一个包含 4 个字节的 16 进制数据数组。 最后,我们使用 uart_read_bytes() 函数接收 4 个字节的 16 进制数据,并将其存储在 rx_buffer 数组中。请注意,此函数将一直等待,直到收到指定数量的字节。如果不希望等待,可以将最后一个参数设置为一个超时值(以毫秒为单位)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

人才程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值