欢迎光临
我们一直在努力

【ESP32-S3 从入门到精通-04】2026 最新串口通信与传感器数据采集实战(UART/I2C/SPI+DHT11+OLED)

关键字:ESP32-S3、ESP-IDF v5.5、UART 串口、I2C 总线、SPI 总线、DHT11 温湿度传感器、SSD1306 OLED 显示屏、物联网数据采集 摘要:本文系统讲解 ESP32-S3 最常用的三种串行通信接口 ——UART、I2C 与 SPI 的工作原理与 ESP-IDF v5.5 实现方法。通过四个循序渐进的实战项目,从基础的串口数据回显入手,逐步深入到 DHT11 温湿度传感器数据采集、SSD1306 OLED 显示屏驱动,最终实现 "传感器采集 + 本地显示 + 串口上传" 的完整物联网数据采集系统。文章最后附上10 + 常见问题解答和硬件接线避坑指南,确保初学者零失败完成所有实验。


写在前面

大家好,我是 EmbeddedCore。上一讲我们学习了 GPIO 与基础外设开发,掌握了 LED 控制、按键检测和 PWM 调光技术。从这一讲开始,我们将进入更精彩的通信与传感器世界。

在物联网项目中,数据采集是核心环节。我们需要通过各种通信接口连接传感器,获取环境数据,然后进行处理和传输。ESP32-S3 提供了丰富的通信外设,其中 UART、I2C 和 SPI 是最常用的三种,几乎所有的传感器和外设都通过这三种接口与 MCU 通信。

本讲将从原理讲起,通过完整可运行的代码,带你一步步掌握这三种通信接口的使用方法,并实现一个实用的温湿度数据采集系统。学完本讲,你将能够独立连接和驱动绝大多数常见的传感器和外设。


一、三大串行通信接口对比与选型

在开始学习之前,我们先来对比一下 UART、I2C 和 SPI 三种通信方式的优缺点和适用场景,帮助你在实际项目中做出正确的选择:

通信方式信号线数量传输速度通信距离设备数量复杂度适用场景
UART 2 条 (TX/RX) 慢 (最高几 Mbps) 远 (可达几十米) 2 个 (点对点) 与电脑、蓝牙模块、GPS 模块通信
I2C 2 条 (SCL/SDA) 中 (最高 4Mbps) 近 (几米) 最多 127 个 连接传感器、OLED 显示屏、EEPROM
SPI 4 条 (SCK/MOSI/MISO/CS) 快 (最高几十 Mbps) 近 (几米) 多个 (取决于 CS 数量) 中高 连接高速外设:LCD 屏幕、Flash、SD 卡

选型建议:

  • 简单的点对点通信优先使用 UART
  • 连接多个低速外设优先使用 I2C(布线简单)
  • 高速数据传输优先使用 SPI

二、UART 串口通信详解

2.1 UART 基本原理

UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器)是一种异步串行通信协议。它不需要时钟信号,而是通过预先约定的波特率来同步数据传输。

UART 通信使用两条信号线:

  • TX(Transmit):发送数据线
  • RX(Receive):接收数据线

通信时,发送方将并行数据转换为串行数据,通过 TX 线发送;接收方通过 RX 线接收串行数据,然后转换为并行数据。

2.2 UART 核心参数配置

UART 通信需要双方约定相同的参数才能正常通信,核心参数包括:

  • 波特率:每秒传输的比特数,常见值有 9600、115200、921600 等
  • 数据位:每个数据帧包含的比特数,通常为 8 位
  • 停止位:数据帧结束的标志,通常为 1 位
  • 校验位:用于错误检测,通常不使用(无校验)

ESP32-S3 有 3 个 UART 控制器(UART0、UART1、UART2),其中 UART0 默认用于与电脑的串口通信(烧录和调试)。

2.3 UART 数据发送与接收

ESP-IDF 提供了简单易用的 UART 操作函数:

// 安装UART驱动
esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, QueueHandle_t *uart_queue, int intr_alloc_flags);

// 配置UART参数
esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config);

// 设置UART引脚
esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int rts_io_num, int cts_io_num);

// 发送数据
int uart_write_bytes(uart_port_t uart_num, const void *src, size_t size);

// 接收数据
int uart_read_bytes(uart_port_t uart_num, void *buf, size_t length, TickType_t ticks_to_wait);

2.4 实战项目 1:串口数据回显

串口数据回显是最基础的 UART 实验,功能是将电脑通过串口发送给 ESP32-S3 的数据原样返回。

完整代码:

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/uart.h"

#define UART_PORT UART_NUM_0
#define TX_PIN GPIO_NUM_43 // ESP32-S3默认UART0 TX引脚
#define RX_PIN GPIO_NUM_44 // ESP32-S3默认UART0 RX引脚
#define BUF_SIZE 1024

void uart_init(void)
{
// 配置UART参数
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,
.source_clk = UART_SCLK_APB
};
uart_param_config(UART_PORT, &uart_config);

// 设置UART引脚
uart_set_pin(UART_PORT, TX_PIN, RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

// 安装UART驱动
uart_driver_install(UART_PORT, BUF_SIZE, BUF_SIZE, 0, NULL, 0);
}

void app_main(void)
{
uart_init();

uint8_t data[BUF_SIZE];

while(1) {
// 读取串口数据
int len = uart_read_bytes(UART_PORT, data, BUF_SIZE – 1, pdMS_TO_TICKS(100));

if(len > 0) {
data[len] = '\\0';
printf("Received: %s", data);

// 将数据原样返回
uart_write_bytes(UART_PORT, data, len);
}
}
}

实验步骤:

  • 编译烧录代码到 ESP32-S3 开发板
  • 打开串口监控工具(如 VSCode 串口监控、串口助手)
  • 设置波特率为 115200,数据位 8,停止位 1,无校验
  • 在发送框中输入任意字符,点击发送
  • 你将看到 ESP32-S3 原样返回你发送的字符

  • 三、I2C 总线通信详解

    3.1 I2C 基本原理

    I2C(Inter-Integrated Circuit,集成电路总线)是一种同步串行通信协议,由飞利浦公司发明。它使用两条信号线:

    • SCL(Serial Clock):时钟线,由主机提供
    • SDA(Serial Data):数据线,用于传输数据

    I2C 总线支持多主机和多从机架构,每个从机都有一个唯一的 7 位地址。通信总是由主机发起,从机根据地址响应。

    I2C 通信的基本流程:

  • 主机发送起始信号
  • 主机发送从机地址 + 读写位
  • 从机发送应答信号
  • 主机或从机发送数据
  • 每发送一个字节,接收方发送应答信号
  • 主机发送停止信号
  • 3.2 ESP32-S3 I2C 控制器

    ESP32-S3 有 2 个 I2C 控制器(I2C0 和 I2C1),都可以配置为主机或从机模式。作为主机时,最高支持 4MHz 的时钟频率。

    3.3 I2C 数据读写操作

    ESP-IDF 提供了两种 I2C 数据读写方式:

  • 简易 API:适用于简单的单字节读写
  • 命令链接 API:适用于复杂的多字节读写
  • 常用 I2C 函数:

    // 配置I2C参数
    esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t *i2c_conf);

    // 安装I2C驱动
    esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_buf_len, size_t slv_tx_buf_len, int intr_alloc_flags);

    // 写入数据到I2C从机
    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从机读取数据
    esp_err_t i2c_master_read_from_device(i2c_port_t i2c_num, uint8_t device_address, uint8_t *read_buffer, size_t read_size, TickType_t ticks_to_wait);

    3.4 实战项目 2:SSD1306 OLED 显示屏驱动

    SSD1306 是一款非常流行的 OLED 显示屏控制器,通常通过 I2C 接口与 MCU 通信。我们将使用 ESP32-S3 驱动一块 0.96 英寸 128×64 分辨率的 SSD1306 OLED 显示屏。

    硬件接线:

    OLED 引脚ESP32-S3 引脚
    VCC 3.3V
    GND GND
    SCL GPIO8
    SDA GPIO9

    完整代码: 首先创建ssd1306.h头文件:

    #ifndef SSD1306_H
    #define SSD1306_H

    #include "driver/i2c.h"

    #define SSD1306_I2C_ADDR 0x3C // OLED默认I2C地址
    #define SSD1306_WIDTH 128
    #define SSD1306_HEIGHT 64

    void ssd1306_init(void);
    void ssd1306_clear_screen(void);
    void ssd1306_set_pixel(uint8_t x, uint8_t y, uint8_t color);
    void ssd1306_set_string(uint8_t line, uint8_t col, const char *str);
    void ssd1306_refresh(void);

    #endif

    然后创建ssd1306.c驱动文件:

    #include "ssd1306.h"
    #include "font.h" // 字库文件,文末提供下载

    static uint8_t ssd1306_buffer[SSD1306_WIDTH * SSD1306_HEIGHT / 8];

    static void ssd1306_write_cmd(uint8_t cmd)
    {
    uint8_t data[2] = {0x00, cmd};
    i2c_master_write_to_device(I2C_NUM_0, SSD1306_I2C_ADDR, data, 2, pdMS_TO_TICKS(100));
    }

    static void ssd1306_write_data(uint8_t data)
    {
    uint8_t buf[2] = {0x40, data};
    i2c_master_write_to_device(I2C_NUM_0, SSD1306_I2C_ADDR, buf, 2, pdMS_TO_TICKS(100));
    }

    void ssd1306_init(void)
    {
    // 初始化命令序列
    ssd1306_write_cmd(0xAE); // 关闭显示
    ssd1306_write_cmd(0xD5); // 设置时钟分频因子
    ssd1306_write_cmd(0x80);
    ssd1306_write_cmd(0xA8); // 设置驱动路数
    ssd1306_write_cmd(0x3F);
    ssd1306_write_cmd(0xD3); // 设置显示偏移
    ssd1306_write_cmd(0x00);
    ssd1306_write_cmd(0x40); // 设置显示开始行
    ssd1306_write_cmd(0x8D); // 电荷泵设置
    ssd1306_write_cmd(0x14);
    ssd1306_write_cmd(0x20); // 设置内存地址模式
    ssd1306_write_cmd(0x00);
    ssd1306_write_cmd(0xA1); // 段重映射设置
    ssd1306_write_cmd(0xC8); // COM扫描方向
    ssd1306_write_cmd(0xDA); // 设置COM硬件引脚配置
    ssd1306_write_cmd(0x12);
    ssd1306_write_cmd(0x81); // 对比度设置
    ssd1306_write_cmd(0xCF);
    ssd1306_write_cmd(0xD9); // 设置预充电周期
    ssd1306_write_cmd(0xF1);
    ssd1306_write_cmd(0xDB); // 设置VCOMH取消选择级别
    ssd1306_write_cmd(0x30);
    ssd1306_write_cmd(0xA4); // 全局显示开启
    ssd1306_write_cmd(0xA6); // 设置显示方式
    ssd1306_write_cmd(0xAF); // 开启显示

    ssd1306_clear_screen();
    ssd1306_refresh();
    }

    void ssd1306_clear_screen(void)
    {
    for(int i = 0; i < sizeof(ssd1306_buffer); i++) {
    ssd1306_buffer[i] = 0x00;
    }
    }

    void ssd1306_set_pixel(uint8_t x, uint8_t y, uint8_t color)
    {
    if(x >= SSD1306_WIDTH || y >= SSD1306_HEIGHT) return;

    if(color) {
    ssd1306_buffer[x + (y / 8) * SSD1306_WIDTH] |= (1 << (y % 8));
    } else {
    ssd1306_buffer[x + (y / 8) * SSD1306_WIDTH] &= ~(1 << (y % 8));
    }
    }

    void ssd1306_set_string(uint8_t line, uint8_t col, const char *str)
    {
    while(*str) {
    for(int i = 0; i < 8; i++) {
    uint8_t data = font8x8[*str – ' '][i];
    for(int j = 0; j < 8; j++) {
    ssd1306_set_pixel(col * 8 + j, line * 8 + i, (data >> j) & 0x01);
    }
    }
    col++;
    str++;
    }
    }

    void ssd1306_refresh(void)
    {
    for(int i = 0; i < 8; i++) {
    ssd1306_write_cmd(0xB0 + i); // 设置页地址
    ssd1306_write_cmd(0x00); // 设置列地址低4位
    ssd1306_write_cmd(0x10); // 设置列地址高4位

    for(int j = 0; j < SSD1306_WIDTH; j++) {
    ssd1306_write_data(ssd1306_buffer[i * SSD1306_WIDTH + j]);
    }
    }
    }

    最后是主程序main.c:

    #include <stdio.h>
    #include "freertos/FreeRTOS.h"
    #include "freertos/task.h"
    #include "driver/i2c.h"
    #include "ssd1306.h"

    #define I2C_MASTER_SCL_IO GPIO_NUM_8
    #define I2C_MASTER_SDA_IO GPIO_NUM_9
    #define I2C_MASTER_NUM I2C_NUM_0
    #define I2C_MASTER_FREQ_HZ 100000

    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_MASTER_NUM, &conf);
    i2c_driver_install(I2C_MASTER_NUM, conf.mode, 0, 0, 0);
    }

    void app_main(void)
    {
    i2c_master_init();
    ssd1306_init();

    ssd1306_clear_screen();
    ssd1306_set_string(0, 0, "ESP32-S3 Demo");
    ssd1306_set_string(2, 0, "I2C OLED Test");
    ssd1306_set_string(4, 0, "Hello World!");
    ssd1306_refresh();

    while(1) {
    vTaskDelay(pdMS_TO_TICKS(1000));
    }
    }

    实验步骤:

  • 按照硬件接线表连接 OLED 显示屏
  • 将ssd1306.h、ssd1306.c和font.h文件添加到工程的main目录下
  • 修改main/CMakeLists.txt文件,将ssd1306.c添加到编译列表中
  • 编译烧录代码
  • 你将看到 OLED 显示屏上显示出文字

  • 四、DHT11 温湿度传感器数据采集

    4.1 DHT11 传感器介绍

    DHT11 是一款常用的温湿度传感器,它内部集成了一个电阻式感湿元件和一个 NTC 测温元件,并与一个 8 位单片机相连。DHT11 通过单总线协议与 MCU 通信,只需要一根数据线。

    DHT11 的技术参数:

    • 温度测量范围:0~50℃,精度 ±2℃
    • 湿度测量范围:20%~90% RH,精度 ±5% RH
    • 采样周期:1 秒

    4.2 DHT11 通信协议

    DHT11 使用单总线协议,通信流程如下:

  • 主机发送起始信号(拉低总线至少 18ms,然后拉高 20~40us)
  • DHT11 发送响应信号(拉低总线 80us,然后拉高 80us)
  • DHT11 发送 40 位数据(5 字节):湿度整数、湿度小数、温度整数、温度小数、校验和
  • 数据发送完毕后,DHT11 拉低总线 50us,然后释放总线
  • 4.3 实战项目 3:DHT11 温湿度数据采集

    硬件接线:

    DHT11 引脚ESP32-S3 引脚
    VCC 3.3V
    GND GND
    DATA GPIO4

    完整代码:

    #include <stdio.h>
    #include "freertos/FreeRTOS.h"
    #include "freertos/task.h"
    #include "driver/gpio.h"
    #include "rom/ets_sys.h"

    #define DHT11_PIN GPIO_NUM_4

    static void dht11_reset(void)
    {
    gpio_set_direction(DHT11_PIN, GPIO_MODE_OUTPUT);
    gpio_set_level(DHT11_PIN, 0);
    ets_delay_us(20000); // 拉低至少18ms
    gpio_set_level(DHT11_PIN, 1);
    ets_delay_us(30); // 拉高20~40us
    }

    static int dht11_check_response(void)
    {
    gpio_set_direction(DHT11_PIN, GPIO_MODE_INPUT);
    int retry = 0;

    while(gpio_get_level(DHT11_PIN) == 1 && retry < 100) {
    retry++;
    ets_delay_us(1);
    }
    if(retry >= 100) return -1;

    retry = 0;
    while(gpio_get_level(DHT11_PIN) == 0 && retry < 100) {
    retry++;
    ets_delay_us(1);
    }
    if(retry >= 100) return -1;

    retry = 0;
    while(gpio_get_level(DHT11_PIN) == 1 && retry < 100) {
    retry++;
    ets_delay_us(1);
    }
    if(retry >= 100) return -1;

    return 0;
    }

    static uint8_t dht11_read_byte(void)
    {
    uint8_t data = 0;

    for(int i = 0; i < 8; i++) {
    while(gpio_get_level(DHT11_PIN) == 0);
    ets_delay_us(40);

    if(gpio_get_level(DHT11_PIN) == 1) {
    data |= (1 << (7 – i));
    }

    while(gpio_get_level(DHT11_PIN) == 1);
    }

    return data;
    }

    int dht11_read_data(float *temperature, float *humidity)
    {
    uint8_t buf[5];

    dht11_reset();
    if(dht11_check_response() != 0) {
    return -1;
    }

    for(int i = 0; i < 5; i++) {
    buf[i] = dht11_read_byte();
    }

    if(buf[0] + buf[1] + buf[2] + buf[3] != buf[4]) {
    return -1;
    }

    *humidity = buf[0] + buf[1] * 0.1;
    *temperature = buf[2] + buf[3] * 0.1;

    return 0;
    }

    void app_main(void)
    {
    gpio_reset_pin(DHT11_PIN);

    float temperature, humidity;

    while(1) {
    if(dht11_read_data(&temperature, &humidity) == 0) {
    printf("Temperature: %.1f C, Humidity: %.1f %%RH\\n", temperature, humidity);
    } else {
    printf("Failed to read DHT11 data\\n");
    }

    vTaskDelay(pdMS_TO_TICKS(2000)); // DHT11采样周期至少1秒
    }
    }

    实验步骤:

  • 按照硬件接线表连接 DHT11 传感器
  • 编译烧录代码
  • 打开串口监控,你将看到每隔 2 秒打印一次温湿度数据

  • 五、综合实战:温湿度数据采集 + OLED 显示 + 串口上传

    现在我们将前面三个实战项目结合起来,实现一个完整的温湿度数据采集系统:

  • 每隔 2 秒读取一次 DHT11 温湿度数据
  • 将数据显示在 OLED 显示屏上
  • 通过串口将数据发送到电脑
  • 完整代码

    #include <stdio.h>
    #include "freertos/FreeRTOS.h"
    #include "freertos/task.h"
    #include "driver/i2c.h"
    #include "driver/gpio.h"
    #include "rom/ets_sys.h"
    #include "ssd1306.h"

    #define I2C_MASTER_SCL_IO GPIO_NUM_8
    #define I2C_MASTER_SDA_IO GPIO_NUM_9
    #define I2C_MASTER_NUM I2C_NUM_0
    #define I2C_MASTER_FREQ_HZ 100000

    #define DHT11_PIN GPIO_NUM_4

    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_MASTER_NUM, &conf);
    i2c_driver_install(I2C_MASTER_NUM, conf.mode, 0, 0, 0);
    }

    // DHT11驱动代码(同上,此处省略)
    static void dht11_reset(void) { … }
    static int dht11_check_response(void) { … }
    static uint8_t dht11_read_byte(void) { … }
    int dht11_read_data(float *temperature, float *humidity) { … }

    void app_main(void)
    {
    i2c_master_init();
    ssd1306_init();
    gpio_reset_pin(DHT11_PIN);

    float temperature, humidity;
    char buf[32];

    ssd1306_clear_screen();
    ssd1306_set_string(0, 0, "ESP32-S3");
    ssd1306_set_string(1, 0, "温湿度监测系统");
    ssd1306_refresh();

    vTaskDelay(pdMS_TO_TICKS(2000));

    while(1) {
    if(dht11_read_data(&temperature, &humidity) == 0) {
    // 串口输出
    printf("Temperature: %.1f C, Humidity: %.1f %%RH\\n", temperature, humidity);

    // OLED显示
    ssd1306_clear_screen();
    ssd1306_set_string(0, 0, "温湿度监测");

    sprintf(buf, "温度: %.1f C", temperature);
    ssd1306_set_string(2, 0, buf);

    sprintf(buf, "湿度: %.1f %%RH", humidity);
    ssd1306_set_string(4, 0, buf);

    ssd1306_refresh();
    } else {
    printf("Failed to read DHT11 data\\n");
    ssd1306_clear_screen();
    ssd1306_set_string(0, 0, "读取失败");
    ssd1306_refresh();
    }

    vTaskDelay(pdMS_TO_TICKS(2000));
    }
    }

    实验效果:

    • OLED 显示屏上显示 "温湿度监测" 标题和实时的温度、湿度数据
    • 串口监控中每隔 2 秒打印一次温湿度数据
    • 用手握住 DHT11 传感器,你会看到温度和湿度数值发生变化

    六、SPI 总线通信简介

    SPI(Serial Peripheral Interface,串行外设接口)是一种高速同步串行通信协议,由摩托罗拉公司发明。它使用四条信号线:

    • SCK(Serial Clock):时钟线,由主机提供
    • MOSI(Master Output, Slave Input):主机输出 / 从机输入
    • MISO(Master Input, Slave Output):主机输入 / 从机输出
    • CS(Chip Select):片选线,用于选择从机

    SPI 总线支持全双工通信,传输速度非常快,最高可达几十 Mbps。ESP32-S3 有 3 个 SPI 控制器(SPI0、SPI1、SPI2、SPI3),其中 SPI0 和 SPI1 用于连接内部 Flash 和 PSRAM,SPI2 和 SPI3 可以用于连接外部外设。

    由于篇幅限制,本讲不详细讲解 SPI 的使用方法,我们将在后续讲解 LCD 显示屏和 SD 卡时再深入介绍。


    七、常见问题解答与避坑指南

    7.1 串口乱码怎么办?

    解决方案:

  • 确保串口监控工具的波特率、数据位、停止位、校验位与代码中配置的一致
  • 检查 USB 线是否接触良好
  • 降低波特率试试
  • 7.2 I2C 通信失败怎么办?

    解决方案:

  • 检查 SCL 和 SDA 引脚是否接反
  • 确保设备地址正确(可以使用 I2C 扫描程序查找设备地址)
  • 检查设备是否上电
  • 降低 I2C 时钟频率试试
  • 7.3 OLED 不显示怎么办?

    解决方案:

  • 检查接线是否正确
  • 检查 OLED 的 I2C 地址是否正确(有些 OLED 的地址是 0x3D)
  • 确保 OLED 的 VCC 接的是 3.3V,不要接 5V
  • 检查初始化命令是否正确
  • 7.4 DHT11 数据读取失败怎么办?

    解决方案:

  • 检查 DATA 引脚是否接对
  • 确保 DHT11 的 VCC 接的是 3.3V,不要接 5V
  • 增加延时时间,DHT11 的采样周期至少 1 秒
  • 检查 DHT11 是否损坏
  • 7.5 如何查找 I2C 设备地址?

    解决方案:使用以下 I2C 扫描程序:

    void i2c_scan(void)
    {
    printf("Scanning I2C bus…\\n");

    for(uint8_t addr = 1; addr < 127; addr++) {
    esp_err_t ret = i2c_master_write_to_device(I2C_NUM_0, addr, NULL, 0, pdMS_TO_TICKS(100));
    if(ret == ESP_OK) {
    printf("I2C device found at address 0x%02X\\n", addr);
    }
    }

    printf("Scan complete\\n");
    }


    八、课后作业

  • 基础练习:实现串口数据回显功能
  • 进阶练习:读取 DHT11 温湿度传感器数据
  • 综合练习:在 OLED 显示屏上显示温湿度数据
  • 挑战练习:实现通过串口发送命令控制 OLED 显示内容的功能

  • 九、下期预告

    第 5 讲将深入学习FreeRTOS 实时操作系统,这是 ESP-IDF 的核心。我们将详细讲解任务创建与管理、消息队列、信号量、互斥锁等核心概念,并通过实战项目演示如何使用 FreeRTOS 实现多任务并发处理,让你的 ESP32-S3 项目更加高效和稳定。


    写在最后

    串口通信和传感器数据采集是物联网开发的基础技能,几乎所有的物联网项目都会用到。希望通过本讲的学习,你能够熟练掌握 UART、I2C 和 SPI 三种通信接口的使用方法,并能够独立连接和驱动常见的传感器和外设。

    本讲用到的font.h字库文件和完整工程代码,我已经上传到了我的 GitHub 仓库,大家可以在评论区留言获取。如果你在学习过程中遇到任何问题,欢迎在评论区留言讨论。

    点赞收藏不迷路,关注我,带你从零基础成为 ESP32-S3 开发高手!

     

    赞(0)
    未经允许不得转载:171主机测评 » 【ESP32-S3 从入门到精通-04】2026 最新串口通信与传感器数据采集实战(UART/I2C/SPI+DHT11+OLED)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址