ESP32+ESP-IDF 使用MQTT协议连接阿里云物联网平台源码分享

ESP32+ESP-IDF 使用MQTT协议连接阿里云物联网平台源码分享

一、源码分享

1、效果展示

2、开发环境搭建

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

3、ESP32添加MQTT组件

3.1、Ctrl+Shift+P打开组件注册表

3.2、搜索mqtt并添加到工程


4、阿里云平台设置

4.1、新建产品

4.2、添加属性



4.3、添加一个设备


5、源码分享

5.1、 main.c

cpp 复制代码
#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 <string.h>
#include <sys/socket.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "lwip/apps/mqtt.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "mqtt_client.h"
#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "esp_log.h"
#include "mqtt_client.h"
#include "esp_netif.h"


#define EXAMPLE_ESP_WIFI_SSID      "VIP"
#define EXAMPLE_ESP_WIFI_PASS      "nimingzi"
#define EXAMPLE_ESP_MAXIMUM_RETRY  5


/* 用户需要根据设备信息完善以下宏定义中的三元组内容 */
#define PRODUCT_KEY         "hiqgz0WYBSj"                                                       /* ProductKey->阿里云颁发的产品唯一标识,11位长度的英文数字随机组合 */
#define DEVICE_NAME         "test"                                                       /* DeviceName->用户注册设备时生成的设备唯一编号,支持系统自动生成,也可支持用户添加自定义编号,产品维度内唯一  */
#define DEVICE_SECRET       "dcd0f171af643b339d4f4248f394ef16"                                  /* DeviceSecret->设备密钥,与DeviceName成对出现,可用于一机一密的认证方案  */
/* MQTT地址与端口 */
#define HOST_NAME           "iot-06z00isf62nazut.mqtt.iothub.aliyuncs.com"                  /* 阿里云域名 */
#define HOST_PORT           1883                                                                /* 阿里云域名端口,固定1883 */
/* 根据三元组内容计算得出的数值 */
#define CLIENT_ID           "hiqgz0WYBSj.test|securemode=2,signmethod=hmacsha256,timestamp=1770624657493|"  /* 客户端ID */
#define USER_NAME           "test&hiqgz0WYBSj"                                          /* 客户端用户名 */
#define PASSWORD            "8c06ec1dcde16a642a8bcb56bc86f4d851915047d3b043691697d2ed619d5f35"                          /* 由MQTT_Password工具计算得出的连接密码 */
/* 发布与订阅 */
#define DEVICE_PUBLISH      "/sys/"PRODUCT_KEY"/"DEVICE_NAME"/thing/event/property/post"                          /* 发布 */
#define DEVICE_SUBSCRIBE    "/"PRODUCT_KEY"/"DEVICE_NAME"/user/get"                             /* 订阅 */
	

#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

/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;

/* The event group allows multiple bits for each event, but we only care about two events:
 * - we are connected to the AP with an IP
 * - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1

static const char *TAG = "mqtt";

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");
    }
}

int g_publish_flag = 0;/* 发布成功标志位 */

char g_lcd_buff[100] = {0};

/**
 * @brief       错误日记
 * @param       message     :错误消息
 * @param       error_code  :错误码
 * @retval      无
 */
static void log_error_if_nonzero(const char *message, int error_code)
{
    if (error_code != 0)
    {
        ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code);
    }
}

/**
 * @brief       注册接收MQTT事件的事件处理程序
 * @param       handler_args:注册到事件的用户数据
 * @param       base        :处理程序的事件库
 * @param       event_id    :接收到的事件的id
 * @param       event_data  :事件的数据
 * @retval      无
 */
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
    ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32 "", base, event_id);
    esp_mqtt_event_handle_t event = event_data;
    esp_mqtt_client_handle_t client = event->client;
    int msg_id;

    switch ((esp_mqtt_event_id_t)event_id)
    {
        case MQTT_EVENT_CONNECTED:      /* 连接事件 */
            ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
            msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_3", 0, 1, 0);
            ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);

            msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
            ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);

            msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
            ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);

            msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
            ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
            g_publish_flag = 1;
            /* 订阅主题 */
            msg_id = esp_mqtt_client_subscribe(client, DEVICE_SUBSCRIBE, 0);
            ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
            break;
        case MQTT_EVENT_DISCONNECTED:   /* 断开连接事件 */

            break;

        case MQTT_EVENT_SUBSCRIBED:     /* 取消事件 */
            ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
            msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
            ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
            break;
        case MQTT_EVENT_UNSUBSCRIBED:   /* 取消订阅事件 */
            ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
            break;
        case MQTT_EVENT_PUBLISHED:      /* 发布事件 */
            ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
            break;
        case MQTT_EVENT_DATA:           /* 接收数据事件 */
            printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
            printf("DATA=%.*s\r\n", event->data_len, event->data);

            break;
        case MQTT_EVENT_ERROR:

            if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT)
            {
                log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
                log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err);
                log_error_if_nonzero("captured as transport's socket errno",  event->error_handle->esp_transport_sock_errno);
                ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
            }

            break;
        default:
            ESP_LOGI(TAG, "Other event id:%d", event->event_id);
            break;
    }
}

/**
 * @brief       lwip_demo进程
 * @param       无
 * @retval      无
 */
void lwip_demo(void)
{
    char mqtt_publish_data[] = "{\"id\": \"123\",\"version\": \"1.0\",\"sys\":{\"ack\":0},\"params\": {\"temperature\":23.6},\"method\": \"thing.event.property.post\"}";
    /* 设置客户端的信息量 */ 
    esp_mqtt_client_config_t mqtt_cfg = {
    .broker.address.hostname = HOST_NAME,                   /* MQTT地址 */
    .broker.address.port = HOST_PORT,                       /* MQTT端口号 */
    .broker.address.transport = MQTT_TRANSPORT_OVER_TCP,    /* TCP模式 */
    .credentials.client_id = CLIENT_ID,                     /* 设备名称 */
    .credentials.username = (char*)USER_NAME,               /* 产品ID */
    .credentials.authentication.password = PASSWORD,        /* 计算出来的密码 */
    };

    esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);

    esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
    esp_mqtt_client_start(client);

    while(1)
    {
        if (g_publish_flag == 1)
        {
            esp_mqtt_client_publish(client,DEVICE_PUBLISH,(char *)mqtt_publish_data,strlen(mqtt_publish_data),1,0);
        }
        
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}


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, "start mqtt demo");
    lwip_demo();

    while(1)
    {

        vTaskDelay(1000);
    }
}

5.2、 参数配置

WiFi参数配置

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

MQTT参数配置

自己自己设备参数进行配置

c 复制代码
/* 用户需要根据设备信息完善以下宏定义中的三元组内容 */
#define PRODUCT_KEY         "hiqgzSj"                                                       /* ProductKey->阿里云颁发的产品唯一标识,11位长度的英文数字随机组合 */
#define DEVICE_NAME         "tst"                                                       /* DeviceName->用户注册设备时生成的设备唯一编号,支持系统自动生成,也可支持用户添加自定义编号,产品维度内唯一  */
#define DEVICE_SECRET       "dcd0f171af339d4f4248f394ef16"                                  /* DeviceSecret->设备密钥,与DeviceName成对出现,可用于一机一密的认证方案  */
/* MQTT地址与端口 */
#define HOST_NAME           "iot-06z00isf62nazut.mqtt.iothub.aliyuncs.com"                  /* 阿里云域名 */
#define HOST_PORT           1883                                                                /* 阿里云域名端口,固定1883 */
/* 根据三元组内容计算得出的数值 */
#define CLIENT_ID           "hiqgz0WYBSj.test|securemode=2,6,timestamp=1770624657493|"  /* 客户端ID */
#define USER_NAME           "test&0WYBSj"                                          /* 客户端用户名 */
#define PASSWORD            "8c06ec1dcde16a642a8bcb56bc861697d2ed619d5f35"                          /* 由MQTT_Password工具计算得出的连接密码 */
/* 发布与订阅 */
#define DEVICE_PUBLISH      "/sys/"PRODUCT_KEY"/"DEVICE_NAME"/thing/event/property/post"                          /* 发布 */
#define DEVICE_SUBSCRIBE    "/"PRODUCT_KEY"/"DEVICE_NAME"/user/get"                             /* 订阅 */

打开设备连接参数查看

二、MQTT协议介绍

1、概述

MQTT 是一种基于发布/订阅 模式的轻量级消息传输协议,专为低带宽、高延迟或不可靠的网络环境设计。它广泛应用于物联网设备之间的通信。

2、核心概念

  • 发布者 (Publisher):负责生成并发送消息的设备或应用。
  • 订阅者 (Subscriber):接收并处理其感兴趣消息的设备或应用。
  • 代理服务器 (Broker) :消息传递的中枢。它接收发布者的消息,并根据主题将其转发给订阅者。
  • 主题 (Topic) :一个分层结构的字符串,代理服务器用它来过滤消息并决定将消息路由给哪些订阅者。例如:home/living_room/temperature

3、工作原理

  1. 订阅者向代理服务器订阅一个或多个主题。
  2. 发布者将消息发布到特定主题。
  3. 代理服务器接收该消息。
  4. 代理服务器查找所有订阅了该主题的订阅者。
  5. 代理服务器将消息转发给这些订阅者。

4、主要特点

  • 轻量高效:协议头部开销小,报文紧凑,节省网络带宽和设备资源。
  • 发布/订阅模型:实现生产者和消费者的解耦,提高系统灵活性和可扩展性。
  • 服务质量等级 (QoS)
    • QoS 0 (最多一次):消息发送一次,不保证送达。无确认。
    • QoS 1 (至少一次):消息确保送达,但可能重复。需要确认。
    • QoS 2 (恰好一次):消息确保送达且不重复。需要两次握手确认,开销最大。
  • 遗嘱消息 (Last Will and Testament, LWT):客户端异常断开时,代理服务器自动向指定主题发布预设消息,通知其他客户端该异常离线。
  • 会话保持:客户端可以指定会话持久化,即使断开重连后也能恢复之前的订阅和未接收的消息 (QoS > 0)。
  • 保留消息 (Retained Message):代理服务器可以为某个主题保留最新的一条消息。新订阅者订阅该主题时,会立即收到这条保留消息。

5、协议版本

目前广泛使用的是 MQTT v3.1.1MQTT v5.0 。v5.0 增加了更多特性,如:

* 原因码 (Reason Codes)

* 会话过期 (Session Expiry)

* 共享订阅 (Shared Subscriptions)

* 用户属性 (User Properties)

* 增强的认证机制

6、安全性

  • 传输层安全:通常结合 TLS/SSL 对通信进行加密。
  • 认证:客户端连接代理服务器时通常需要提供用户名和密码。
  • 授权:代理服务器可控制客户端对主题的发布和订阅权限。

7、优点

  • 非常适合资源受限的嵌入式设备和网络条件不稳定的场景。
  • 扩展性好,易于集成大量设备。
  • 模型简单,易于理解和实现。

8、缺点

  • 代理服务器是潜在的单点故障和性能瓶颈。
  • 协议本身不定义消息负载格式,需要应用层自行协商。

9、典型应用场景

  • 物联网 (IoT):传感器数据上报、远程设备控制。
  • 移动应用:消息推送。
  • 实时数据监控:如股票行情、实时日志。
  • M2M 通信 (机器对机器)。

三、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 的关键。

相关推荐
Web3VentureView18 小时前
X Space AMA回顾|预测熊市底部:当市场寻找价格,SYNBO正在构建未来
人工智能·物联网·金融·web3·区块链
小灰灰搞电子1 天前
ESP32 使用ESP-IDF 驱动红外遥控器源码分享
esp32·红外遥控
拍客圈1 天前
阿里云cdn配置(Discuz! X3.5版)
阿里云·云计算
勇敢牛牛_1 天前
ESP32 + Rust 开发的简易语音助手
rust·嵌入式·esp32·语音助手
国产化创客2 天前
ESP32+Web实现智能气象站
前端·物联网·智能家居·智能硬件
上海合宙LuatOS2 天前
LuatOS核心库API——【hmeta 】硬件元数据
单片机·嵌入式硬件·物联网·算法·音视频·硬件工程·哈希算法
TDengine (老段)2 天前
TDengine IDMP 数据可视化 7. 事件列表
大数据·数据库·人工智能·物联网·时序数据库·tdengine·涛思数据
BY组态2 天前
智捷云3D组态:打造沉浸式工业可视化解决方案
运维·物联网·3d·web组态
会算数的⑨2 天前
Spring AI Alibaba 学习(三):Graph Workflow 深度解析(上篇)
java·人工智能·后端·学习·阿里云·agent·saa