ESP32 使用ESP-IDF实现Modbus TCP从机通信源码分享

ESP32 使用ESP-IDF实现Modbus TCP从机通信源码分享

一、源码分享

1、效果展示

2、开发环境搭建

参考我这篇博文:VS Code 在线安装ESP-IDF,ESP32开发环境搭建详细教程

3、源码分享

3.1、modbus组件添加

Ctrl + Shift+P打开组件管理器

搜索modbus

选中espressif/esp-modbus点击install

等待加载完成

3.2、 main.c

c 复制代码
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/projdefs.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"

#include "lwip/err.h"
#include "lwip/sys.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"

#include "mbcontroller.h"

#define EXAMPLE_ESP_WIFI_SSID      "VIP"
#define EXAMPLE_ESP_WIFI_PASS      "nimingzi"
#define EXAMPLE_ESP_MAXIMUM_RETRY  5
#define SERVER_IP              "192.168.11.218"
#define SERVER_PORT            6000

#if CONFIG_ESP_STATION_EXAMPLE_WPA3_SAE_PWE_HUNT_AND_PECK
#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_HUNT_AND_PECK
#define EXAMPLE_H2E_IDENTIFIER ""
#elif CONFIG_ESP_STATION_EXAMPLE_WPA3_SAE_PWE_HASH_TO_ELEMENT
#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_HASH_TO_ELEMENT
#define EXAMPLE_H2E_IDENTIFIER CONFIG_ESP_WIFI_PW_ID
#elif CONFIG_ESP_STATION_EXAMPLE_WPA3_SAE_PWE_BOTH
#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_BOTH
#define EXAMPLE_H2E_IDENTIFIER CONFIG_ESP_WIFI_PW_ID
#endif
#if CONFIG_ESP_WIFI_AUTH_OPEN
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_OPEN
#elif CONFIG_ESP_WIFI_AUTH_WEP
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WEP
#elif CONFIG_ESP_WIFI_AUTH_WPA_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA2_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA_WPA2_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_WPA2_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA3_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA3_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA2_WPA3_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_WPA3_PSK
#elif CONFIG_ESP_WIFI_AUTH_WAPI_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WAPI_PSK
#endif
static EventGroupHandle_t s_wifi_event_group;

#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1

static const char *TAG = "wifi station";

static int s_retry_num = 0;


static void event_handler(void* arg, esp_event_base_t event_base,
                                int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        esp_wifi_connect();
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
            esp_wifi_connect();
            s_retry_num++;
            ESP_LOGI(TAG, "retry to connect to the AP");
        } else {
            xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
        }
        ESP_LOGI(TAG,"connect to the AP fail");
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
        s_retry_num = 0;
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
    }
}

void wifi_init_sta(void)
{
    s_wifi_event_group = xEventGroupCreate();

    ESP_ERROR_CHECK(esp_netif_init());

    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_sta();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_got_ip));

    wifi_config_t wifi_config = {
        .sta = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .password = EXAMPLE_ESP_WIFI_PASS,

            .threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD,
            .sae_pwe_h2e = ESP_WIFI_SAE_MODE,
            .sae_h2e_identifier = EXAMPLE_H2E_IDENTIFIER,
        },
    };
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
    ESP_ERROR_CHECK(esp_wifi_start() );

    ESP_LOGI(TAG, "wifi_init_sta finished.");

    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
            WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
            pdFALSE,
            pdFALSE,
            portMAX_DELAY);


    if (bits & WIFI_CONNECTED_BIT) {
        ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    } else if (bits & WIFI_FAIL_BIT) {
        ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    } else {
        ESP_LOGE(TAG, "UNEXPECTED EVENT");
    }
}
typedef enum {
    MODBUS_FC_READ_COILS = 0x01,
    MODBUS_FC_READ_DISCRETE_INPUTS = 0x02,
    MODBUS_FC_READ_HOLDING_REGISTERS = 0x03,
    MODBUS_FC_READ_INPUT_REGISTERS = 0x04,
    MODBUS_FC_WRITE_SINGLE_COIL = 0x05,
    MODBUS_FC_WRITE_SINGLE_REGISTER = 0x06,
    MODBUS_FC_WRITE_MULTIPLE_COILS = 0x0F,
    MODBUS_FC_WRITE_MULTIPLE_REGISTERS = 0x10
} modbus_function_code_t;


#define MB_READ_MASK                        (MB_EVENT_INPUT_REG_RD \
                                                | MB_EVENT_HOLDING_REG_RD \
                                                | MB_EVENT_DISCRETE_RD \
                                                | MB_EVENT_COILS_RD)
#define MB_WRITE_MASK                       (MB_EVENT_HOLDING_REG_WR \
                                                | MB_EVENT_COILS_WR)
#define MB_READ_WRITE_MASK                  (MB_READ_MASK | MB_WRITE_MASK)

void app_main(void)
{
    //Initialize NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
      ESP_ERROR_CHECK(nvs_flash_erase());
      ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    if (CONFIG_LOG_MAXIMUM_LEVEL > CONFIG_LOG_DEFAULT_LEVEL) {
        esp_log_level_set("wifi", CONFIG_LOG_MAXIMUM_LEVEL);
    }

    ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
    wifi_init_sta();
    vTaskDelay(pdTICKS_TO_MS(3000));

    ESP_LOGI(TAG, "modbus start!");

   vTaskDelay(pdTICKS_TO_MS(3000));
   ESP_LOGE(TAG, "wifi connected, start modbus slave!");

    static void *slave_handle = NULL;
    mb_communication_info_t tcp_slave_config_1 = {
        .tcp_opts.port = 502,
        .tcp_opts.mode = MB_TCP,
        .tcp_opts.addr_type = MB_IPV4,
        .tcp_opts.ip_addr_table = NULL, // Bind to any address
        .tcp_opts.ip_netif_ptr = (void *)esp_netif_get_default_netif(),
        .tcp_opts.uid = 1
    };
    mb_register_area_descriptor_t reg_area = {0}; 
    uint16_t buffer[20] = {0}; 
    mb_param_info_t reg_info; 

    esp_err_t err = mbc_slave_create_tcp(&tcp_slave_config_1, &slave_handle);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "mbc_slave_create_tcp fail, returns(0x%x).", (int)err);
        return;
    }
    if (slave_handle == NULL) {
        ESP_LOGE(TAG, "mbc_slave_create_tcp fail, slave_handle is NULL.");
        return;
    }

    reg_area.type = MB_PARAM_HOLDING; 
    reg_area.start_offset = 0; 
    reg_area.address = (void *)&buffer[0]; 
    reg_area.size = 20; 
    reg_area.access = MB_ACCESS_RW;
    err = mbc_slave_set_descriptor(slave_handle, reg_area);
    if( err != ESP_OK) {
        ESP_LOGE(TAG, "mbc_slave_set_descriptor fail, returns(0x%x).", (int)err);
        return;
    }

    err = mbc_slave_start(slave_handle);
    if( err != ESP_OK) {
        ESP_LOGE(TAG, "mbc_slave_start fail, returns(0x%x).", (int)err);
        return;
    }

    while(1)
    {
        for(int i = 0; i < 20; i++)
        {
            buffer[i] ++;
        }

        (void)mbc_slave_check_event(slave_handle, MB_READ_WRITE_MASK);      
        ESP_ERROR_CHECK_WITHOUT_ABORT(mbc_slave_get_param_info(slave_handle, &reg_info, 10));  
        const char *rw_str = (reg_info.type & MB_READ_MASK) ? "READ" : "WRITE";  
        if (reg_info.type & (MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD)) {
            ESP_LOGI(TAG, "OBJ %p, HOLDING %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
                     slave_handle,
                     rw_str,
                     (unsigned)reg_info.time_stamp,
                     (unsigned)reg_info.mb_offset,
                     (unsigned)reg_info.type,
                     (int)reg_info.address,
                     (unsigned)reg_info.size);
        }



        vTaskDelay(pdTICKS_TO_MS(10));
    }
}

3.3、 参数更改

修改WiFi名称和密码

c 复制代码
#define EXAMPLE_ESP_WIFI_SSID      "VIP"
#define EXAMPLE_ESP_WIFI_PASS      "nimingzi"

修改modbus读取地址和长度

c 复制代码
reg_area.type = MB_PARAM_HOLDING; 
reg_area.start_offset = 0; 
reg_area.address = (void *)&buffer[0]; 
reg_area.size = 20; 
reg_area.access = MB_ACCESS_RW;

二、modbus TCP详解

1、概述

Modbus TCP 是一种基于 TCP/IP 网络的应用层通信协议,是 Modbus 协议族在以太网上的实现。它设计用于工业自动化领域,允许不同设备(如 PLC、SCADA 系统、传感器、执行器)之间进行主从式通信。其核心思想是将传统的 Modbus RTU(串行)报文帧封装在 TCP/IP 数据包中传输。

2、通信模型

Modbus TCP 采用 客户端/服务器(主/从) 模型:

  1. 客户端 (Client / Master):通常是上位机(如 HMI、SCADA 系统、编程软件),负责发起通信请求(读写命令)。
  2. 服务器 (Server / Slave):通常是现场设备(如 PLC、RTU、智能仪表),负责接收并处理客户端的请求,并返回响应。

3、报文帧结构

Modbus TCP 报文在 Modbus RTU 报文的基础上增加了 MBAP 头 (Modbus Application Header),去掉了 RTU 的地址和 CRC 校验(由 TCP 层保证可靠性)。

一个完整的 Modbus TCP 报文帧结构如下:

字段名 字节数 描述
事务处理标识符 2 用于请求和响应的匹配。客户端生成,服务器在响应中复制该值。
协议标识符 2 固定为 0x0000,表示 Modbus 协议。
长度字段 2 表示其后剩余字节数(从单元标识符开始到数据结束)。
单元标识符 1 用于标识服务器设备(相当于 RTU 中的从站地址)。通常 0xFF 表示广播。
Modbus PDU 可变 Modbus 协议数据单元。包含功能码和具体数据(请求或响应)。
  • Modbus PDU (Protocol Data Unit) 结构:
    • 功能码 (Function Code - 1字节):指示要执行的操作类型(读、写等)。
    • 数据域 (Data Field - 可变长度) :包含请求或响应的具体数据(如寄存器地址、数量、实际值等)。

4、主要功能码

Modbus 定义了多种功能码,用于访问不同类型的寄存器/数据区:

功能码 (十进制) 名称 操作对象 访问权限 (典型)
01 (0x01) 读线圈状态 离散量输出 (线圈) 读/写
02 (0x02) 读输入状态 离散量输入 只读
03 (0x03) 读保持寄存器 保持寄存器 读/写
04 (0x04) 读输入寄存器 输入寄存器 只读
05 (0x05) 写单个线圈 单个离散量输出 (线圈)
06 (0x06) 写单个保持寄存器 单个保持寄存器
15 (0x0F) 写多个线圈 多个离散量输出 (线圈)
16 (0x10) 写多个保持寄存器 多个保持寄存器

5、通信流程示例 (读保持寄存器)

  1. 客户端请求 (Request)
    • 事务处理标识符:0x0001 (示例)
    • 协议标识符:0x0000
    • 长度:0x0006 (1字节单元ID + 5字节PDU)
    • 单元标识符:0x01 (目标从站地址)
    • PDU:
      • 功能码:0x03 (读保持寄存器)
      • 起始地址高字节:0x00 (寄存器 40001)
      • 起始地址低字节:0x00
      • 寄存器数量高字节:0x00
      • 寄存器数量低字节:0x02 (读 2 个寄存器)
  2. 服务器响应 (Response - 成功)
    • 事务处理标识符:0x0001 (与请求一致)
    • 协议标识符:0x0000
    • 长度:0x05 (1字节单元ID + 4字节PDU)
    • 单元标识符:0x01
    • PDU:
      • 功能码:0x03 (与请求一致)
      • 字节计数:0x04 (2个寄存器 * 2字节/寄存器)
      • 寄存器 40001 值高字节:0x12
      • 寄存器 40001 值低字节:0x34
      • 寄存器 40002 值高字节:0x56
      • 寄存器 40002 值低字节:0x78

6、特点

  1. 标准化与开放性:协议标准公开,易于实现和集成。
  2. 简单性:报文结构清晰,易于理解和调试。
  3. 广泛应用:工业领域事实上的标准协议之一,设备支持广泛。
  4. 基于 TCP/IP:可以利用现有以太网基础设施,传输距离远,速率高。

7、缺点与注意事项

  1. 缺乏安全性:原始协议未定义加密或强认证机制,易受攻击(如中间人攻击、数据篡改)。工业环境中需结合防火墙、VPN 等安全措施。后续有 Modbus Secure 扩展。
  2. 无数据类型定义:协议本身不定义数据类型(如整数、浮点数、字符串),由应用层约定。
  3. 无时间戳:原始协议不携带报文时间戳。
  4. 广播限制:虽然支持广播,但服务器无法对广播请求做出响应。
  5. 实时性:依赖于 TCP 的可靠传输,可能不如某些专有实时以太网协议快。

三、ESP-IDF详解

1、ESP32 概述

ESP32 是由乐鑫科技(Espressif Systems)推出的一款高性能、低功耗、高集成度的 Wi-Fi & 蓝牙双模系统级芯片(SoC)。它广泛应用于物联网(IoT)、智能家居、工业控制等领域。其关键特性包括:

  • 双核处理器(通常为 Xtensa LX6,某些型号为 RISC-V)
  • 集成 Wi-Fi (802.11 b/g/n) 和蓝牙 (包括经典蓝牙和低功耗蓝牙 BLE)
  • 丰富的外设接口: S P I SPI SPI, I 2 C I2C I2C, I 2 S I2S I2S, U A R T UART UART, A D C ADC ADC, D A C DAC DAC, P W M PWM PWM, 触摸传感器等
  • 充足的内存(RAM 和 Flash 选项多样)
  • 强大的安全特性(如加密加速器)
  • 超低功耗设计,支持多种休眠模式

2、 ESP-IDF 详解

ESP-IDF (Espressif IoT Development Framework) 是乐鑫官方为 ESP32、ESP32-S 系列、ESP32-C 系列等芯片提供的开发框架和 SDK(软件开发工具包)。它是开发基于 ESP32 芯片应用程序的首选和官方推荐工具。

2.1 、ESP-IDF 的核心组件与架构

ESP-IDF 是一个分层、模块化的框架:

  • 硬件抽象层 (HAL): 提供对芯片硬件资源(如 GPIO、UART、SPI、I2C、定时器、ADC、DAC、RTC、Wi-Fi、蓝牙等)进行操作的统一接口,屏蔽底层硬件细节。
  • 驱动 (Drivers): 在 HAL 之上,提供更易用、功能更丰富的设备驱动(如 SPI Flash 驱动、SD 卡驱动、以太网驱动等)。
  • FreeRTOS: ESP-IDF 深度集成了开源的 FreeRTOS 实时操作系统内核。它提供了任务管理、队列、信号量、软件定时器、中断管理等机制,充分利用 ESP32 的多核特性(任务可以在不同核心上运行)。
  • 中间件:
    • Wi-Fi 协议栈: 实现 Wi-Fi 的 Station(客户端)、SoftAP(接入点)、Promiscuous(监听)模式。
    • 蓝牙协议栈: 实现经典蓝牙和低功耗蓝牙 (BLE) 的各种角色(如 GATT Client/Server, GAP Central/Peripheral)。
    • TCP/IP 协议栈 (lwIP): 轻量级的 TCP/IP 协议栈,支持 IPv4/IPv6 (部分型号)、DHCP、DNS、Socket API 等。
    • 文件系统 (FATFS/VFS): 支持在 SPI Flash 或外部存储设备上使用 FAT 文件系统。
    • 加密库: 提供 AES、SHA、RSA 等加密算法的软件和硬件加速实现。
    • HTTP/WebSocket/MQTT 等协议库: 方便构建网络应用。
  • 应用程序: 用户编写的业务逻辑代码,运行在 FreeRTOS 的任务中,通过调用下层 API 实现功能。

2.2 、ESP-IDF 开发环境与工具链

  • 工具链: 基于 GNU GCC 编译器(针对 Xtensa 或 RISC-V 架构)。
  • 构建系统: 使用 CMake (早期版本使用 GNU Make)。开发者编写 CMakeLists.txt 文件来定义项目结构、源文件、依赖组件等。
  • 配置工具: menuconfig。这是一个基于文本的图形化配置工具(类似于 Linux Kernel 的 make menuconfig),用于配置 ESP-IDF 的众多选项,如:
    • 选择目标芯片型号
    • 配置 Wi-Fi/BT 参数
    • 调整 FreeRTOS 设置(任务栈大小、优先级等)
    • 配置日志输出级别和方式
    • 配置内存布局
    • 启用/禁用特定功能和外设驱动
  • 核心工具 - idf.py 这是 ESP-IDF 提供的命令行工具,用于执行构建、烧录、调试、监视串口输出等几乎所有开发任务。常用命令如:
    • idf.py set-target esp32 (设置目标芯片)
    • idf.py menuconfig (启动配置工具)
    • idf.py build (编译项目)
    • idf.py -p PORT flash (烧录固件到设备,PORT 为串口,如 COM3 或 /dev/ttyUSB0)
    • idf.py -p PORT monitor (启动串口监视器,查看设备日志输出)
    • idf.py fullclean (彻底清理构建目录)

2.3 、ESP-IDF 开发流程简述

  1. 环境搭建: 在 Windows、Linux 或 macOS 上安装 ESP-IDF 开发环境(包括工具链、Python、Git 等)。
  2. 创建项目: 使用 idf.py create-project 或复制示例项目模板。
  3. 编写代码:main 目录下编写应用程序代码 (通常是 main.capp_main() 函数)。
  4. 配置项目: 运行 idf.py menuconfig 根据需求进行配置。
  5. 编译项目: 运行 idf.py build 生成可执行固件 (.bin 文件)。
  6. 烧录固件: 将 ESP32 开发板连接到电脑,运行 idf.py -p PORT flash 将固件烧录到设备 Flash 中。
  7. 监视输出: 运行 idf.py -p PORT monitor 查看设备运行日志,进行调试。可以使用 ESP_LOGx (如 ESP_LOGI, ESP_LOGE) 函数打印不同级别的日志。

2.4、 示例代码结构 (最简单的 Hello World)

c 复制代码
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"

static const char *TAG = "MAIN";

void app_main(void)
{
    while (1) {
        ESP_LOGI(TAG, "Hello World!"); // 打印 Info 级别日志
        vTaskDelay(pdMS_TO_TICKS(1000)); // 延时 1000 毫秒 (FreeRTOS 延时)
    }
}

2.5、 优势与特点

  • 官方支持: 由芯片原厂维护,更新及时,与新芯片特性同步快。
  • 功能全面: 提供对 ESP32 所有硬件特性和外设的底层访问。
  • 性能优化: 针对 ESP32 硬件进行了深度优化(如 Wi-Fi/BT 共存)。
  • 稳定性高: 经过大量商业产品验证。
  • 社区活跃: 用户多,社区支持好,问题容易找到解决方案。
  • 文档完善: 官方提供详尽的 API 参考指南、编程指南和示例代码。
  • 模块化: 易于扩展和复用代码,方便管理大型项目。
  • 开源免费: 基于 Apache 2.0 许可证。

2.6 、适用场景

ESP-IDF 适用于需要深度控制硬件、追求高性能、高稳定性或需要使用 ESP32 特有功能(如超低功耗协处理器 ULP)的应用开发。对于快速原型开发,也可以考虑基于 ESP-IDF 构建的更高级框架(如 Arduino for ESP32、MicroPython),但这些框架最终都依赖于 ESP-IDF 的底层功能。

3、总结

ESP-IDF 是开发 ESP32 系列芯片的强大、灵活且功能完备的官方框架。它提供了从硬件操作到网络协议栈的全套解决方案,结合 FreeRTOS 实现了高效的多任务处理。虽然其学习曲线相对陡峭,尤其是对于不熟悉嵌入式开发和 RTOS 的开发者,但它提供了最直接、最强大的方式来充分利用 ESP32 的潜力,是开发复杂或高性能 ESP32 应用的基石。掌握 idf.py 工具链和 menuconfig 配置是使用 ESP-IDF 的关键。

相关推荐
百锦再3 小时前
Java的TCP和UDP实现详解
java·spring boot·tcp/ip·struts·spring cloud·udp·kafka
小灰灰搞电子5 小时前
ESP32 使用ESP-IDF驱动DS1302时钟芯片源码分享
esp32·ds1302
cur1es8 小时前
【TCP 协议的相关特性】
java·网络·网络协议·tcp/ip·tcp·滑动窗口·连接管理
戏舟的嵌入式开源笔记9 小时前
ESP32电子相册
esp32·嵌入式软件
tianyagukechat1 天前
rockylinux9.5 配置IP
java·网络·tcp/ip
8125035331 天前
DNS监控:生产实践
linux·网络·网络协议·tcp/ip·计算机网络
hhzz1 天前
云服务器ECS的高可用部署方案----弹性公网IP和负载均衡的操作
服务器·tcp/ip·负载均衡·ecs·云服务器
白太岁1 天前
Muduo:(4) 主从 Reactor、事件循环、跨线程无锁唤醒及其线程池
c++·网络协议·tcp/ip
白太岁1 天前
Muduo:(5) 主 Reactor 之 Acceptor 与 SubReactor 的分发
服务器·网络·c++·网络协议·tcp/ip