1. 边缘网关硬件平台选型与接口识别

边缘网关硬件平台选型与接口识别 学习卡片

任务定义

本案例面向工业IoT边缘网关开发的第一阶段:硬件平台选型与接口识别。目标是为后续固件开发选定一款具体、可获取的硬件平台,并完整识别其核心接口资源,形成一份可直接指导驱动开发与外围电路设计的接口清单。任务边界限定为:选定平台、识别接口、输出接口映射关系,不涉及具体业务代码编写。

平台选型结论

选用ESP32-WROOM-32E模组作为边缘网关核心处理器。选型理由:双核240MHz主频满足边缘协议转换算力需求;集成Wi-Fi 802.11 b/g/n与蓝牙4.2,可同时承担上行云连接与下行近场调试;34个可编程GPIO、3路UART、2路I2C、1路SPI、2路12-bit SAR ADC、1路DAC,接口种类覆盖工业传感器采集、继电器控制、RS485总线扩展等典型网关外设需求;模组内置4MB Flash,支持OTA固件升级。开发板选用ESP32-DevKitC V4作为调试载体,其板载USB-UART桥接芯片CP2102提供串口烧录与日志通道。

接口资源识别

下表列出本网关设计中将实际使用的接口及其功能分配。该映射关系是后续各案例(RS485采集、Modbus协议栈移植、MQTT上云等)的硬件基础。

接口类型物理引脚功能分配电气特性
UART0GPIO1(TX0), GPIO3(RX0)日志输出/固件烧录3.3V TTL,默认115200-8-N-1
UART2GPIO17(TX2), GPIO16(RX2)RS485总线(外接MAX3485)3.3V TTL,经收发器转差分
I2C0GPIO21(SDA), GPIO22(SCL)温湿度传感器SHT303.3V,上拉4.7kΩ,速率400kHz
SPI2GPIO18(SCK), GPIO19(MISO), GPIO23(MOSI), GPIO5(CS)SD卡存储(数据记录)3.3V,模式0,速率10MHz
ADC1_CH0GPIO364-20mA电流环采样(外接采样电阻)0-3.3V模拟输入,12-bit
GPIO输出GPIO25, GPIO26继电器控制(外接ULN2003驱动)3.3V推挽输出,最大40mA
GPIO输入GPIO27干接点状态检测(外接光耦隔离)3.3V输入,内部上拉
电源5V/VIN, 3V3, GND系统供电与对外供电USB 5V输入,板载LDO输出3.3V/500mA

接口识别验证代码

以下代码用于验证上述接口映射是否与硬件实际连接一致。程序依次初始化各接口并执行回环或状态读取测试,结果通过UART0输出。该代码仅做接口可用性确认,不包含业务逻辑。

// file: hw_verify.c
// 依赖:ESP-IDF v4.4 及以上版本
// 构建:idf.py build flash monitor

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/uart.h"
#include "driver/i2c.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "driver/adc.h"
#include "esp_adc_cal.h"

#define UART2_TX_PIN  17
#define UART2_RX_PIN  16
#define I2C_SDA_PIN   21
#define I2C_SCL_PIN   22
#define SPI_SCK_PIN   18
#define SPI_MISO_PIN  19
#define SPI_MOSI_PIN  23
#define SPI_CS_PIN     5
#define RELAY1_PIN    25
#define RELAY2_PIN    26
#define DI_PIN        27
#define ADC_PIN       ADC1_CHANNEL_0  // GPIO36

// UART2 回环测试:将TX2与RX2短接后,发送0xA5应收到0xA5
static void uart2_loopback_test(void) {
    uart_config_t uart_cfg = {
        .baud_rate = 9600,
        .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_2, &uart_cfg);
    uart_set_pin(UART_NUM_2, UART2_TX_PIN, UART2_RX_PIN, -1, -1);
    uart_driver_install(UART_NUM_2, 256, 256, 0, NULL, 0);

    uint8_t tx_data = 0xA5, rx_data = 0;
    uart_write_bytes(UART_NUM_2, &tx_data, 1);
    int len = uart_read_bytes(UART_NUM_2, &rx_data, 1, pdMS_TO_TICKS(100));
    printf("[UART2] %s (发送0x%02X, 接收0x%02X)\n",
           (len == 1 && rx_data == tx_data) ? "PASS" : "FAIL", tx_data, rx_data);
    uart_driver_delete(UART_NUM_2);
}

// I2C0 扫描:SHT30地址为0x44,检测到则通信正常
static void i2c_scan_test(void) {
    i2c_config_t conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = I2C_SDA_PIN,
        .scl_io_num = I2C_SCL_PIN,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = 400000
    };
    i2c_param_config(I2C_NUM_0, &conf);
    i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0);

    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (0x44 << 1) | I2C_MASTER_WRITE, true);
    i2c_master_stop(cmd);
    esp_err_t ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, pdMS_TO_TICKS(100));
    i2c_cmd_link_delete(cmd);
    printf("[I2C0] %s (SHT30地址0x44)\n", (ret == ESP_OK) ? "PASS" : "FAIL");
    i2c_driver_delete(I2C_NUM_0);
}

// SPI2 写读测试:CS拉低后向MOSI发0x55,MISO应收到0x55(短接MOSI与MISO)
static void spi_loopback_test(void) {
    spi_bus_config_t bus_cfg = {
        .mosi_io_num = SPI_MOSI_PIN,
        .miso_io_num = SPI_MISO_PIN,
        .sclk_io_num = SPI_SCK_PIN,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1
    };
    spi_bus_initialize(SPI2_HOST, &bus_cfg, SPI_DMA_CH_AUTO);

    spi_device_interface_config_t dev_cfg = {
        .clock_speed_hz = 10 * 1000 * 1000,
        .mode = 0,
        .spics_io_num = SPI_CS_PIN,
        .queue_size = 1
    };
    spi_device_handle_t spi_dev;
    spi_bus_add_device(SPI2_HOST, &dev_cfg, &spi_dev);

    uint8_t tx_data = 0x55, rx_data = 0;
    spi_transaction_t trans = {
        .length = 8,
        .tx_buffer = &tx_data,
        .rx_buffer = &rx_data
    };
    esp_err_t ret = spi_device_transmit(spi_dev, &trans);
    printf("[SPI2] %s (发送0x%02X, 接收0x%02X)\n",
           (ret == ESP_OK && rx_data == tx_data) ? "PASS" : "FAIL", tx_data, rx_data);
    spi_bus_remove_device(spi_dev);
    spi_bus_free(SPI2_HOST);
}

// GPIO输出与输入测试:将GPIO25与GPIO27短接,输出高电平后读取DI引脚
static void gpio_di_test(void) {
    gpio_config_t out_cfg = {
        .pin_bit_mask = (1ULL << RELAY1_PIN) | (1ULL << RELAY2_PIN),
        .mode = GPIO_MODE_OUTPUT,
        .pull_up_en = GPIO_PULLUP_DISABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE
    };
    gpio_config(&out_cfg);

    gpio_config_t in_cfg = {
        .pin_bit_mask = (1ULL << DI_PIN),
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = GPIO_PULLUP_ENABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE
    };
    gpio_config(&in_cfg);

    gpio_set_level(RELAY1_PIN, 1);
    vTaskDelay(pdMS_TO_TICKS(10));
    int level = gpio_get_level(DI_PIN);
    printf("[GPIO] %s (GPIO25输出高, GPIO27读到%d)\n", (level == 1) ? "PASS" : "FAIL", level);
    gpio_set_level(RELAY1_PIN, 0);
}

// ADC 电压读取:GPIO36悬空或接已知电压,打印原始值与换算电压
static void adc_read_test(void) {
    adc1_config_width(ADC_WIDTH_BIT_12);
    adc1_config_channel_atten(ADC_PIN, ADC_ATTEN_DB_11);
    esp_adc_cal_characteristics_t cal;
    esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 1100, &cal);

    int raw = adc1_get_raw(ADC_PIN);
    uint32_t voltage = esp_adc_cal_raw_to_voltage(raw, &cal);
    printf("[ADC1] raw=%d, voltage=%dmV (GPIO36)\n", raw, voltage);
}

void app_main(void) {
    printf("=== 硬件接口识别验证开始 ===\n");
    uart2_loopback_test();
    i2c_scan_test();
    spi_loopback_test();
    gpio_di_test();
    adc_read_test();
    printf("=== 验证结束 ===\n");
}

接口连接拓扑

ESP32-WROOM-32E 双核240MHz / Wi-Fi+BLE 3×UART / 2×I2C / 1×SPI 12-bit ADC / 34×GPIO 4MB Flash / 520KB SRAM UART0 调试通道 GPIO1(TX) / GPIO3(RX) 115200-8-N-1 RS485 总线 GPIO17(TX2) / GPIO16(RX2) MAX3485 收发器 I2C0 传感器 GPIO21(SDA) / GPIO22(SCL) SHT30 温湿度 0x44 SPI2 SD卡存储 GPIO18/19/23/5 10MHz 模式0 继电器输出 GPIO25 / GPIO26 ULN2003 驱动 干接点输入 GPIO27 光耦隔离 4-20mA 采样 GPIO36 (ADC1_CH0) 采样电阻 150Ω 电源系统 USB 5V → 3.3V LDO 3.3V/500mA 输出

验证方法与判定标准

硬件准备:将GPIO17与GPIO16短接(UART2回环);GPIO23与GPIO19短接(SPI回环);GPIO25与GPIO27短接(GPIO输出→输入测试);GPIO36悬空或接已知直流电压(如1.5V电池正极,负极接GND)。

执行步骤:

  1. 使用ESP-IDF环境执行 idf.py set-target esp32 后编译烧录:idf.py build flash monitor;
  2. 观察串口终端输出,逐项核对测试结果。

判定标准:终端依次打印以下内容即判定接口识别与映射验证通过:

[UART2] PASS (发送0xA5, 接收0xA5)
[I2C0] PASS (SHT30地址0x44)
[SPI2] PASS (发送0x55, 接收0x55)
[GPIO] PASS (GPIO25输出高, GPIO27读到1)
[ADC1] raw=xxx, voltage=yyymV (GPIO36)

其中ADC的raw与voltage数值取决于GPIO36所接电压,若悬空则读数不定属正常现象。若某项打印FAIL,需检查对应物理连接或引脚映射配置。