06 - 通信协议

I2C、SPI、UART 通信实现

I2C 总线

硬件连接

        ESP32
        ┌─────┐
   SCL ─┤GPIO22├─►──────►──────►───┐
   SDA ─┬GPIO21├─►──────►──────►───┤
        └─────┘                      │
                                    │
                    ┌───────────────┘
                    │   (接上拉电阻 4.7kΩ 到 3.3V)
                    ▼
              ┌─────────┐
              │  传感器  │
              │  设备地址 │
              └─────────┘

I2C 主机模式

#include "driver/i2c.h"
 
#define I2C_MASTER_SCL_IO 22
#define I2C_MASTER_SDA_IO 21
#define I2C_MASTER_FREQ_HZ 100000
#define I2C_PORT I2C_NUM_0
 
void i2c_master_init(void)
{
    i2c_config_t conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = I2C_MASTER_SDA_IO,
        .scl_io_num = I2C_MASTER_SCL_IO,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = I2C_MASTER_FREQ_HZ
    };
    i2c_param_config(I2C_PORT, &conf);
    i2c_driver_install(I2C_PORT, conf.mode, 0, 0, 0);
}
 
// 写入数据
esp_err_t i2c_write(uint8_t device_addr, uint8_t reg_addr, uint8_t *data, size_t len)
{
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (device_addr << 1) | I2C_MASTER_WRITE, true);
    i2c_master_write_byte(cmd, reg_addr, true);
    i2c_master_write(cmd, data, len, true);
    i2c_master_stop(cmd);
 
    esp_err_t ret = i2c_master_cmd_begin(I2C_PORT, cmd, pdMS_TO_TICKS(1000));
    i2c_cmd_link_delete(cmd);
    return ret;
}
 
// 读取数据
esp_err_t i2c_read(uint8_t device_addr, uint8_t reg_addr, uint8_t *data, size_t len)
{
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
 
    // 先写入寄存器地址
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (device_addr << 1) | I2C_MASTER_WRITE, true);
    i2c_master_write_byte(cmd, reg_addr, true);
 
    // 读取数据
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (device_addr << 1) | I2C_MASTER_READ, true);
    i2c_master_read(cmd, data, len, I2C_MASTER_LAST_NACK);
    i2c_master_stop(cmd);
 
    esp_err_t ret = i2c_master_cmd_begin(I2C_PORT, cmd, pdMS_TO_TICKS(1000));
    i2c_cmd_link_delete(cmd);
    return ret;
}

常用 I2C 设备地址

设备地址 (7位)
BMP2800x76 / 0x77
AHT100x38
SHTC30x70
MPU60500x68
SSD13060x3C / 0x3D

SPI 总线

硬件连接

        ESP32
        ┌─────┐
  MOSI ─┤GPIO23├─►─────►─────►───►
  MISO ─┤GPIO19├─◄─────◄─────◄───◄
   CLK ─┤GPIO18├─►─────►─────►───►
    CS ─┤GPIO5 ├─►─────►─────►───►
        └─────┘

SPI 主机模式

#include "driver/spi_master.h"
 
#define SPI_HOST_ID VSPI_HOST
 
void spi_master_init(void)
{
    spi_bus_config_t buscfg = {
        .mosi_io_num = GPIO_NUM_23,
        .miso_io_num = GPIO_NUM_19,
        .sclk_io_num = GPIO_NUM_18,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = 4096
    };
    spi_bus_initialize(SPI_HOST_ID, &buscfg, SPI_DMA_CH_AUTO);
}
 
// 添加从设备
void spi_device_init(void)
{
    spi_device_interface_config_t devcfg = {
        .command_bits = 0,
        .address_bits = 0,
        .dummy_bits = 0,
        .clock_speed_hz = 1 * 1000 * 1000,  // 1MHz
        .mode = 0,
        .spics_io_num = GPIO_NUM_5,
        .queue_size = 7
    };
 
    spi_device_handle_t handle;
    spi_bus_add_device(SPI_HOST_ID, &devcfg, &handle);
}
 
// SPI 传输
esp_err_t spi_transfer(uint8_t *tx_data, uint8_t *rx_data, size_t len)
{
    spi_transaction_t trans = {
        .length = len * 8,
        .tx_buffer = tx_data,
        .rx_buffer = rx_data
    };
 
    return spi_device_transmit(handle, &trans);
}

UART 串口

初始化配置

#include "driver/uart.h"
 
#define UART_NUM UART_NUM_0
#define TX_PIN 1
#define RX_PIN 3
 
void uart_init(void)
{
    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, &uart_config);
    uart_set_pin(UART_NUM, TX_PIN, RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
    uart_driver_install(UART_NUM, 1024, 1024, 0, NULL, 0);
}
 
// 发送数据
void uart_send(const char *data)
{
    uart_write_bytes(UART_NUM, data, strlen(data));
}
 
// 接收数据
void uart_receive(void)
{
    uint8_t data[128];
    int length = uart_read_bytes(UART_NUM, data, sizeof(data), pdMS_TO_TICKS(1000));
 
    if (length > 0) {
        data[length] = '\0';
        printf("Received: %s\n", data);
    }
}

带队列的异步接收

#include "freertos/queue.h"
 
static QueueHandle_t uart_queue;
 
void uart_init_with_queue(void)
{
    uart_config_t 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_CTS_RTS,
        .rx_flow_ctrl_thresh = 122
    };
 
    uart_param_config(UART_NUM, &config);
    uart_set_pin(UART_NUM, GPIO_NUM_1, GPIO_NUM_3, GPIO_NUM_19, GPIO_NUM_22);
    uart_driver_install(UART_NUM, 2048, 2048, 20, &uart_queue, 0);
 
    // 创建任务处理接收
    xTaskCreate(uart_task, "uart_rx", 2048, NULL, 10, NULL);
}
 
void uart_task(void *pvParameters)
{
    uart_event_t event;
    uint8_t *data = (uint8_t *)malloc(1024);
 
    while (1) {
        if (xQueueReceive(uart_queue, &event, portMAX_DELAY) == pdTRUE) {
            if (event.type == UART_DATA) {
                int len = uart_read_bytes(UART_NUM, data, event.size, 0);
                data[len] = '\0';
                printf("Received %d bytes: %s\n", len, data);
            }
        }
    }
    free(data);
}

参考资料

官方文档

技术参考

图片参考

I2C 总线连接图


相关链接

反向链接

进阶学习


下一步