1. ESP32静态IP配置与ModbusTCP从机通信实验概述
在工业控制和物联网应用中,ESP32作为一款高性价比的Wi-Fi/蓝牙双模芯片,经常需要实现稳定的网络通信。动态IP分配(DHCP)虽然方便,但在以下场景中静态IP配置更为可靠:
- 设备需要固定IP以便主站系统持续访问
- 工业现场网络可能不提供DHCP服务
- 需要避免IP变动导致的通信中断
本实验将基于ESP-IDF v5.5.1开发框架,通过修改protocol_examples_common组件,为ESP32增加静态IP配置功能,并实现ModbusTCP从机通信。最终达到的效果是:
- 设备启动时可选择DHCP或静态IP模式
- 静态IP参数通过menuconfig界面配置
- 支持以太网和Wi-Fi双网卡静态IP设置
- 提供稳定的ModbusTCP从机服务接口
2. 开发环境准备与工程配置
2.1 基础环境搭建
确保已安装以下工具链:
- ESP-IDF v5.5.1(2024年3月发布)
- 支持ESP32的编译工具链
- Python 3.7或更高版本
- CMake 3.16或更高版本
验证环境:
bash复制get-idf
idf.py --version
cmake --version
2.2 示例工程移植
从ESP-IDF示例库中获取基础工程:
bash复制cp -r $IDF_PATH/examples/protocols/sockets/tcp_server .
cd tcp_server
关键移植步骤:
- 复制组件配置文件:
bash复制mkdir -p components/protocol_examples_common
cp $IDF_PATH/examples/common_components/protocol_examples_common/idf_component.yml components/protocol_examples_common/
- 修改工程CMakeLists.txt,添加组件依赖:
cmake复制# 在原有内容后追加
set(EXTRA_COMPONENT_DIRS components)
list(APPEND REQUIRES protocol_examples_common)
- 编译验证:
bash复制idf.py build
此时可能会出现关于IPv6的警告,属于正常现象,不影响后续开发。
3. 静态IP功能实现
3.1 Kconfig配置选项添加
在protocol_examples_common/Kconfig中添加静态IP配置选项,位置选择在EXAMPLE_CONNECT_IPV4配置之前:
kconfig复制choice EXAMPLE_CONNECT_IP_TYPE
prompt "IP Address Type"
default EXAMPLE_CONNECT_DHCP
help
Select IP address allocation method
config EXAMPLE_CONNECT_DHCP
bool "DHCP (Automatic)"
help
Obtain IP address from DHCP server
config EXAMPLE_CONNECT_STATIC_IP
bool "Static IP (Manual)"
help
Configure static IP address manually
endchoice
config EXAMPLE_STATIC_IP_ADDR
string "Static IP Address"
default "192.168.1.100"
depends on EXAMPLE_CONNECT_STATIC_IP
help
Example: 192.168.1.100
config EXAMPLE_STATIC_NETMASK
string "Netmask"
default "255.255.255.0"
depends on EXAMPLE_CONNECT_STATIC_IP
help
Example: 255.255.255.0
config EXAMPLE_STATIC_GW
string "Gateway"
default "192.168.1.1"
depends on EXAMPLE_CONNECT_STATIC_IP
help
Example: 192.168.1.1
3.2 核心功能实现
在protocol_examples_common.c中添加静态IP设置函数:
c复制#if CONFIG_EXAMPLE_CONNECT_STATIC_IP
esp_err_t example_set_static_ip(esp_netif_t *netif)
{
esp_netif_ip_info_t ip_info = {0};
// 转换字符串IP为二进制格式
if(esp_ip4addr_aton(CONFIG_EXAMPLE_STATIC_IP_ADDR, &ip_info.ip) != 1) {
ESP_LOGE(TAG, "Invalid static IP format");
return ESP_ERR_INVALID_ARG;
}
// 设置子网掩码和网关
esp_ip4addr_aton(CONFIG_EXAMPLE_STATIC_NETMASK, &ip_info.netmask);
esp_ip4addr_aton(CONFIG_EXAMPLE_STATIC_GW, &ip_info.gw);
// 停止DHCP客户端
esp_err_t ret = esp_netif_dhcpc_stop(netif);
if(ret != ESP_OK && ret != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) {
ESP_LOGE(TAG, "Failed to stop DHCP client");
return ret;
}
// 应用静态IP配置
ret = esp_netif_set_ip_info(netif, &ip_info);
if(ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set static IP");
return ret;
}
ESP_LOGI(TAG, "Static IP configured: %s", CONFIG_EXAMPLE_STATIC_IP_ADDR);
return ESP_OK;
}
#endif
3.3 网络接口适配
修改example_connect()函数,增加静态IP支持:
c复制esp_err_t example_connect(void)
{
#if CONFIG_EXAMPLE_CONNECT_ETHERNET
if(example_ethernet_connect() != ESP_OK) {
return ESP_FAIL;
}
#if CONFIG_EXAMPLE_CONNECT_STATIC_IP
esp_netif_t *eth_netif = esp_netif_get_handle_from_ifkey("ETH_DEF");
if(eth_netif) {
example_set_static_ip(eth_netif);
}
#endif
#endif
#if CONFIG_EXAMPLE_CONNECT_WIFI
if(example_wifi_connect() != ESP_OK) {
return ESP_FAIL;
}
#if CONFIG_EXAMPLE_CONNECT_STATIC_IP
esp_netif_t *wifi_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
if(wifi_netif) {
example_set_static_ip(wifi_netif);
}
#endif
#endif
return ESP_OK;
}
4. ModbusTCP从机实现
4.1 Modbus协议栈集成
使用开源的FreeModbus库:
- 添加组件依赖:
bash复制cd components
git clone https://github.com/cwalter-at/freemodbus.git
- 配置Modbus参数:
kconfig复制config MB_TCP_PORT
int "Modbus TCP port"
default 502
help
Standard Modbus TCP port is 502
config MB_TCP_MAX_CLIENTS
int "Max TCP clients"
default 5
range 1 10
help
Maximum number of concurrent Modbus TCP connections
4.2 从机服务初始化
在main.c中添加ModbusTCP初始化代码:
c复制#include "mbcontroller.h"
#include "mb_tcp.h"
#define MB_TCP_PORT CONFIG_MB_TCP_PORT
void app_main(void)
{
// 网络初始化
ESP_ERROR_CHECK(example_connect());
// Modbus控制器初始化
mb_communication_info_t comm_info = {
.port = MB_TCP_PORT,
.mode = MB_MODE_TCP,
.slave_addr = 1 // 从机地址
};
ESP_ERROR_CHECK(mbc_master_init_tcp(&comm_info));
ESP_ERROR_CHECK(mbc_master_setup((void*)&comm_info));
// 注册Modbus数据区
mb_register_area_descriptor_t coil_area = {
.start_offset = 0,
.type = MB_PARAM_COIL,
.address = (void*)coil_regs,
.size = sizeof(coil_regs)
};
mbc_master_set_descriptor(&coil_area);
// 启动Modbus栈
ESP_ERROR_CHECK(mbc_master_start());
ESP_LOGI(TAG, "ModbusTCP slave started on port %d", MB_TCP_PORT);
}
4.3 数据区处理
定义Modbus数据存储区并实现读写回调:
c复制// 保持寄存器存储区(100个寄存器)
static uint16_t holding_regs[100] = {0};
// 寄存器读写回调
static esp_err_t reg_read(uint16_t addr, void *value, uint16_t len)
{
if(addr >= sizeof(holding_regs)/sizeof(holding_regs[0])) {
return ESP_ERR_INVALID_ARG;
}
memcpy(value, &holding_regs[addr], len);
return ESP_OK;
}
static esp_err_t reg_write(uint16_t addr, void *value, uint16_t len)
{
if(addr >= sizeof(holding_regs)/sizeof(holding_regs[0])) {
return ESP_ERR_INVALID_ARG;
}
memcpy(&holding_regs[addr], value, len);
return ESP_OK;
}
5. 系统集成与测试
5.1 菜单配置界面
运行idf.py menuconfig配置网络参数:
- 进入"Example Connection Configuration"
- 选择IP分配方式:DHCP或Static IP
- 设置静态IP参数(如选择Static IP)
- 配置Modbus TCP端口(默认502)
5.2 功能验证步骤
- 烧录程序到ESP32:
bash复制idf.py -p /dev/ttyUSB0 flash monitor
- 网络连接验证:
- 检查串口日志中的IP地址信息
- 使用ping测试网络连通性
- Modbus通信测试:
- 使用Modbus Poll等工具连接ESP32
- 测试各功能码(03读保持寄存器,06写单个寄存器等)
- 验证数据读写正确性
5.3 常见问题排查
- 静态IP无法ping通:
- 检查网线连接和物理层状态
- 确认IP地址与局域网同网段
- 验证网关和子网掩码设置
- Modbus通信超时:
- 确认防火墙未阻止502端口
- 检查网络延迟和带宽
- 验证从机地址设置
- 寄存器读写异常:
- 检查地址范围是否越界
- 验证数据区初始化状态
- 确认字节序处理正确
6. 性能优化与生产建议
6.1 内存优化配置
调整FreeRTOS任务堆栈:
c复制// 在sdkconfig.defaults中设置
CONFIG_FREERTOS_TCPIP_TASK_STACK_SIZE=4096
CONFIG_MB_CONTROLLER_STACK_SIZE=3072
6.2 看门狗配置
添加硬件看门狗支持:
c复制#include "esp_task_wdt.h"
void app_main(void)
{
// 初始化任务看门狗
esp_task_wdt_init(30, true);
// 添加当前任务到看门狗监控
esp_task_wdt_add(NULL);
// 主循环中定期喂狗
while(1) {
esp_task_wdt_reset();
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
6.3 生产环境建议
- 安全加固:
- 启用ModbusTCP身份验证
- 实现寄存器访问权限控制
- 添加通信加密层(如TLS)
- 可靠性增强:
- 实现断网自动重连
- 添加心跳包检测机制
- 支持配置参数掉电保存
- 维护接口:
- 实现Web配置页面
- 支持固件OTA升级
- 添加诊断日志功能
提示:在工业现场部署时,建议使用带隔离的以太网模块(如LAN8720A)以提高抗干扰能力,同时注意做好接地处理。