暂存
This commit is contained in:
@ -74,6 +74,15 @@ extern "C" {
|
||||
比如:设备A烧录时改为 0x01,设备B烧录时改为 0x02
|
||||
========================================================= */
|
||||
#define MY_DEVICE_ID 0x02
|
||||
|
||||
/* =========================================================
|
||||
🚀 开发调试开关
|
||||
TEST_A701:
|
||||
- 1: 测试环境 (A701室/本地测试),使用 192.168.6.x 网段
|
||||
- 0: 生产环境 (实船/现场部署),使用 192.168.0.x 网段
|
||||
========================================================= */
|
||||
#define TEST_A701 1
|
||||
|
||||
/* USER CODE END EM */
|
||||
|
||||
/* Exported functions prototypes ---------------------------------------------*/
|
||||
|
||||
50
Core/Inc/modbus_tcp_client.h
Normal file
50
Core/Inc/modbus_tcp_client.h
Normal file
@ -0,0 +1,50 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file modbus_tcp_client.h
|
||||
* @brief Modbus TCP 客户端模块头文件 (基于 W5500)
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __MODBUS_TCP_CLIENT_H
|
||||
#define __MODBUS_TCP_CLIENT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "main.h"
|
||||
|
||||
/* Modbus TCP 配置 */
|
||||
#if TEST_A701
|
||||
#define MODBUS_SERVER_IP {192, 168, 6, 4} /* A701 测试服务器 */
|
||||
#else
|
||||
#define MODBUS_SERVER_IP {192, 168, 0, 1} /* 现场生产服务器 */
|
||||
#endif
|
||||
|
||||
#define MODBUS_SERVER_PORT 502
|
||||
#define MODBUS_UNIT_ID 1
|
||||
#define MODBUS_POLL_INTERVAL 2000 /* 轮询间隔 (ms) */
|
||||
|
||||
/* 寄存器定义 */
|
||||
#define TARGET_REG_ADDR 30 /* 逻辑 40031 */
|
||||
|
||||
/* 客户端状态枚举 */
|
||||
typedef enum {
|
||||
MODBUS_STATE_IDLE,
|
||||
MODBUS_STATE_CONNECTING,
|
||||
MODBUS_STATE_SEND_QUERY,
|
||||
MODBUS_STATE_WAIT_RESPONSE,
|
||||
MODBUS_STATE_PROCESS_DATA,
|
||||
MODBUS_STATE_ERROR_RETRY
|
||||
} modbus_client_state_t;
|
||||
|
||||
/**
|
||||
* @brief 初始化 Modbus TCP 客户端
|
||||
* @param sn: W5500 Socket 编号
|
||||
*/
|
||||
void ModbusTCP_Client_Init(uint8_t sn);
|
||||
|
||||
/**
|
||||
* @brief Modbus TCP 客户端任务处理 (主循环调用)
|
||||
*/
|
||||
void ModbusTCP_Client_Task(void);
|
||||
|
||||
#endif
|
||||
@ -47,6 +47,7 @@
|
||||
#include "wiz_interface.h"
|
||||
#include "wizchip_conf.h"
|
||||
#include "loopback.h"
|
||||
#include "modbus_tcp_client.h"
|
||||
#endif
|
||||
extern void wiz_timer_handler(void);
|
||||
#if (RF433_MODE == RF433_MODE_TX) || (RF433_MODE == RF433_MODE_BOTH)
|
||||
@ -263,8 +264,16 @@ int main(void)
|
||||
|
||||
printf("[DEBUG] 4. 进入 network_init()\r\n");
|
||||
network_init(ethernet_buf, &default_net_info);
|
||||
printf("[DEBUG] 5. network_init() 成功返回!\r\n");
|
||||
printf("wizchip UDP example started\r\n");
|
||||
printf("[DEBUG] 5. network_init() 成功返回!\n");
|
||||
|
||||
printf("--- Socket Status Diagnostic ---\n");
|
||||
for (int i=0; i<8; i++) {
|
||||
printf("Socket %d SR: 0x%02X\n", i, getSn_SR(i));
|
||||
}
|
||||
printf("--------------------------------\n");
|
||||
|
||||
printf("Modbus TCP Client starting\n");
|
||||
ModbusTCP_Client_Init(1); // 暂时使用 Socket 1 进行测试,避开可能被污染的 Socket 0
|
||||
#endif
|
||||
/* ======================================= */
|
||||
|
||||
@ -307,9 +316,9 @@ int main(void)
|
||||
rf433_rx_app_task();
|
||||
#endif
|
||||
|
||||
/* W5500 UDP回环任务 */
|
||||
/* W5500 UDP回环任务(为了测试 PING 功能,放到了单独的 Socket 2) */
|
||||
#if USE_W5500
|
||||
loopback_udps(SOCKET_ID, ethernet_buf, local_port);
|
||||
loopback_udps(2, ethernet_buf, local_port);
|
||||
#endif
|
||||
|
||||
|
||||
@ -389,9 +398,8 @@ int main(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
// (D) W5500 以太网轮询处理 (Type 0x55)
|
||||
#if USE_W5500
|
||||
loopback_udps(SOCKET_ID, ethernet_buf, local_port);
|
||||
ModbusTCP_Client_Task();
|
||||
#endif
|
||||
|
||||
/* USER CODE END WHILE */
|
||||
|
||||
175
Core/Src/modbus_tcp_client.c
Normal file
175
Core/Src/modbus_tcp_client.c
Normal file
@ -0,0 +1,175 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file modbus_tcp_client.c
|
||||
* @brief Modbus TCP 客户端模块实现 (针对寄存器 40031 轮询)
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "modbus_tcp_client.h"
|
||||
#include "socket.h"
|
||||
#include "wizchip_conf.h"
|
||||
#include "main.h"
|
||||
#include "debug_log.h"
|
||||
#include <string.h>
|
||||
|
||||
/* 私有变量 */
|
||||
static uint8_t g_sn = 0;
|
||||
static modbus_client_state_t g_state = MODBUS_STATE_IDLE;
|
||||
static uint32_t g_last_tick = 0;
|
||||
static uint16_t g_transaction_id = 0;
|
||||
|
||||
/* 服务器信息 */
|
||||
static uint8_t dest_ip[4] = MODBUS_SERVER_IP;
|
||||
static uint16_t dest_port = MODBUS_SERVER_PORT;
|
||||
|
||||
/**
|
||||
* @brief 构造 Modbus TCP 请求包 (FC 03)
|
||||
*/
|
||||
static uint16_t build_read_request(uint8_t *buf, uint16_t addr, uint16_t qty)
|
||||
{
|
||||
g_transaction_id++;
|
||||
|
||||
/* MBAP Header */
|
||||
buf[0] = (uint8_t)(g_transaction_id >> 8);
|
||||
buf[1] = (uint8_t)(g_transaction_id & 0xFF);
|
||||
buf[2] = 0x00; /* Protocol ID (0 for Modbus) */
|
||||
buf[3] = 0x00;
|
||||
buf[4] = 0x00; /* Length (6 bytes follow UnitID) */
|
||||
buf[5] = 0x06;
|
||||
buf[6] = MODBUS_UNIT_ID;
|
||||
|
||||
/* PDU */
|
||||
buf[7] = 0x03; /* Function Code: Read Holding Registers */
|
||||
buf[8] = (uint8_t)(addr >> 8);
|
||||
buf[9] = (uint8_t)(addr & 0xFF);
|
||||
buf[10] = (uint8_t)(qty >> 8);
|
||||
buf[11] = (uint8_t)(qty & 0xFF);
|
||||
|
||||
return 12;
|
||||
}
|
||||
|
||||
void ModbusTCP_Client_Init(uint8_t sn)
|
||||
{
|
||||
g_sn = sn;
|
||||
g_state = MODBUS_STATE_IDLE;
|
||||
g_last_tick = HAL_GetTick();
|
||||
|
||||
/* 动态重新加载配置,防止静态初始化带来的宏定义未生效问题 */
|
||||
uint8_t ip[4] = MODBUS_SERVER_IP;
|
||||
dest_ip[0] = ip[0]; dest_ip[1] = ip[1]; dest_ip[2] = ip[2]; dest_ip[3] = ip[3];
|
||||
dest_port = MODBUS_SERVER_PORT;
|
||||
|
||||
LOG_INFO("MODBUS", "Client initialized on Socket %d, Target: %d.%d.%d.%d:%d",
|
||||
sn, dest_ip[0], dest_ip[1], dest_ip[2], dest_ip[3], dest_port);
|
||||
}
|
||||
|
||||
void ModbusTCP_Client_Task(void)
|
||||
{
|
||||
uint8_t tmp_buf[128]; // 临时接收缓存
|
||||
uint16_t len; // 接收长度
|
||||
int32_t ret; // 返回值
|
||||
|
||||
switch (g_state) // 客户端状态机切换
|
||||
{
|
||||
case MODBUS_STATE_IDLE: // 空闲状态
|
||||
if (HAL_GetTick() - g_last_tick >= MODBUS_POLL_INTERVAL) { // 检查轮询间隔 (2秒)
|
||||
g_state = MODBUS_STATE_CONNECTING; // 切换到连接状态
|
||||
}
|
||||
break;
|
||||
|
||||
case MODBUS_STATE_CONNECTING: // 连接中状态
|
||||
{
|
||||
uint8_t sr = getSn_SR(g_sn);
|
||||
switch(sr) // 获取当前 Socket 状态
|
||||
{
|
||||
case SOCK_CLOSED: // 如果 Socket 已关闭
|
||||
// 打开 TCP 模式的 Socket,分配随机本地端口以避免冲突
|
||||
if (socket(g_sn, Sn_MR_TCP, 50000 + (HAL_GetTick() % 10000), 0x00) == g_sn) {
|
||||
LOG_DEBUG("MODBUS", "Socket opened");
|
||||
}
|
||||
break;
|
||||
|
||||
case SOCK_INIT: // Socket 初始化成功,开始连接
|
||||
LOG_INFO("MODBUS", "Connecting to %d.%d.%d.%d:%d",
|
||||
dest_ip[0], dest_ip[1], dest_ip[2], dest_ip[3], dest_port);
|
||||
ret = connect(g_sn, dest_ip, dest_port); // 发起连接请求
|
||||
if (ret != SOCK_OK) {
|
||||
LOG_ERROR("MODBUS", "Connect failed: %d", ret);
|
||||
close(g_sn);
|
||||
g_state = MODBUS_STATE_IDLE;
|
||||
g_last_tick = HAL_GetTick();
|
||||
}
|
||||
break;
|
||||
|
||||
case SOCK_ESTABLISHED: // 连接已建立
|
||||
LOG_INFO("MODBUS", "TCP Connected!");
|
||||
g_state = MODBUS_STATE_SEND_QUERY; // 切换到发送请求状态
|
||||
break;
|
||||
|
||||
case SOCK_CLOSE_WAIT: // 对方已关闭连接
|
||||
disconnect(g_sn); // 本地断开连接
|
||||
break;
|
||||
|
||||
default:
|
||||
if (HAL_GetTick() % 5000 == 0) { // 每 5 秒打印一次未处理的状态
|
||||
LOG_WARN("MODBUS", "Unhandled socket state: 0x%02X", sr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MODBUS_STATE_SEND_QUERY: // 发送查询请求状态
|
||||
len = build_read_request(tmp_buf, TARGET_REG_ADDR, 1); // 构造 Modbus TCP FC03 报文
|
||||
ret = send(g_sn, tmp_buf, len); // 发送 TCP 数据
|
||||
if (ret > 0) { // 发送成功
|
||||
LOG_DEBUG("MODBUS", "Request sent (TID: %d)", g_transaction_id);
|
||||
g_state = MODBUS_STATE_WAIT_RESPONSE; // 切换到等待响应状态
|
||||
g_last_tick = HAL_GetTick(); // 更新计时器
|
||||
} else { // 发送失败
|
||||
LOG_ERROR("MODBUS", "Send failed, reconnecting...");
|
||||
close(g_sn); // 关闭 Socket
|
||||
g_state = MODBUS_STATE_IDLE; // 返回空闲重试
|
||||
}
|
||||
break;
|
||||
|
||||
case MODBUS_STATE_WAIT_RESPONSE: // 等待响应状态
|
||||
if ((len = getSn_RX_RSR(g_sn)) > 0) { // 检查是否有数据到达
|
||||
if (len > sizeof(tmp_buf)) len = sizeof(tmp_buf); // 防止缓存溢出
|
||||
ret = recv(g_sn, tmp_buf, len); // 接收数据
|
||||
if (ret > 0) { // 接收成功
|
||||
g_state = MODBUS_STATE_PROCESS_DATA; // 切换到处理数据状态
|
||||
}
|
||||
} else if (HAL_GetTick() - g_last_tick > 3000) { // 等待超时 (3秒)
|
||||
LOG_WARN("MODBUS", "Response timeout");
|
||||
close(g_sn); // 关闭连接
|
||||
g_state = MODBUS_STATE_IDLE; // 返回空闲重试
|
||||
}
|
||||
break;
|
||||
|
||||
case MODBUS_STATE_PROCESS_DATA: // 处理数据状态
|
||||
/* 校验响应 (检查 MBAP 长度、功能码等) */
|
||||
if (len >= 9 && tmp_buf[7] == 0x03) { // 基本校验
|
||||
uint16_t reg_val = (tmp_buf[9] << 8) | tmp_buf[10]; // 提取寄存器值
|
||||
LOG_INFO("MODBUS", "Read Register %d OK: 0x%04X", TARGET_REG_ADDR + 40001, reg_val);
|
||||
|
||||
/* 🚀 关键步骤:通过 433 无线转发结果 */
|
||||
uint8_t payload[2]; // 构造 433 负载
|
||||
payload[0] = tmp_buf[9]; // 寄存器高位
|
||||
payload[1] = tmp_buf[10]; // 寄存器低位
|
||||
RF433_SendPacket(PROTO_TYPE_NET, payload, 2); // 打包并通过无线发出
|
||||
|
||||
g_state = MODBUS_STATE_IDLE; // 处理完成,返回空闲
|
||||
g_last_tick = HAL_GetTick(); // 记录本次完成时间
|
||||
} else { // 响应格式非法
|
||||
LOG_ERROR("MODBUS", "Invalid response format");
|
||||
g_state = MODBUS_STATE_IDLE; // 返回空闲
|
||||
g_last_tick = HAL_GetTick(); // 更新计时
|
||||
}
|
||||
break;
|
||||
|
||||
default: // 异常保护
|
||||
g_state = MODBUS_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user