全部例程

W55MH32作为HTTP服务器

W55MH32

更新于 2026年9月16日

本篇总结

本例程在 W55MH32 上实现 HTTP 服务器,通过浏览器修改开发板的网络地址信息。

🔑 KEIL MDK、UART调试、硬件TOE引擎、HTTP、DHCP

硬件平台:本例程基于 W55MH32L-EVB 开发板运行。

采购推荐:点击前往 WIZnet 官方淘宝店铺 选购 W55MH32L-EVB

本示例演示如何在 W55MH32 上通过 HTTP(超文本传输协议)实现 Web 服务器功能。开发板监听 80 端口,PC 浏览器访问其 IP 即可打开配置页面,提交表单后新参数写入 EEPROM 并重启生效。

前置工具准备

开始本例程前,请确认以下工具已安装:

HTTP 协议简介

HTTP(HyperText Transfer Protocol)是一种用于分布式、协作式、超媒体信息系统的应用层协议,基于 TCP/IP 通信协议来传递数据,是万维网数据通信的基础。它采用请求-响应模型:客户端发起请求,服务器处理后返回响应;本身无状态,每次请求独立。

HTTP 常用的请求方法有 GET 和 POST:

方法参数位置数据大小安全性典型用途
GETURL 查询字符串受 URL 长度限制明文显示,较低获取资源
POST请求体无明显限制相对安全提交数据

GET 请求格式如下:

GET <Request-URI> HTTP/<Version>
<Headers>
<Blank Line>

POST 请求格式如下(多了一个 Body):

POST <Request-URI> HTTP/<Version>
<Headers>
<Blank Line>
<Body>

HTTP 响应由状态行、响应头和响应体三部分组成。状态码分五类:1xx 信息性、2xx 成功、3xx 重定向、4xx 客户端错误、5xx 服务器错误。一个简单的 HTML 页面示例:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple Page</title>
<style>
body { font-family: Arial, sans-serif; text-align: center; padding: 20px; }
button { padding: 10px 20px; cursor: pointer; }
</style>
</head>
<body>
<h1>Hello, Web!</h1>
<p>Click the button for a surprise.</p>
<button onclick="alert('You clicked the button!')">Click Me</button>
</body>
</html>

Web 页面交互中最常用的表单提交示例:

<form action="/submit" method="post">
<input type="text" name="username" placeholder="Enter your name">
<button type="submit">Submit</button>
</form>

AJAX 异步交互示例:

fetch('/api/data', {
method: 'GET'
})
.then(response => response.json())
.then(data => console.log(data));

W55MH32 的优势

W55MH32 SDK 内置了完整的 HTTP Server 库(httpServer.c/h),Socket 状态机、请求解析、响应发送全部由库函数处理。你只需要:注册网页内容 → 初始化 HTTP Server → 在主循环调用 httpServer_run()。CGI 回调函数处理 POST 提交的参数。

硬件连接与拓扑

请注意:

PC 和开发板需接入同一路由器(同一网段)。路由器需开启 DHCP 服务(家用路由器默认开启)。

  1. Micro USB 线连接 DEBUG USB 口到 PC(供电 + 调试串口)
  2. 网线连接开发板 RJ45 网口 到路由器 LAN 口
┌───────────────────────────────────┐
│ 路由器(DHCP Server) │
│ 192.168.1.1 │
└────┬──────────────────┬───────────┘
│ │
┌────┴──────────┐ ┌───┴───────────┐
│ W55MH32 │ │ PC │
│ (HTTP Server) │ │ (浏览器访问) │
│ :80 │ │ │
└───────────────┘ └───────────────┘
↑
DEBUG USB ──→ WIZ UartTool
网络拓扑:路由器分配 IP,开发板运行 HTTP Server,PC 浏览器访问配置页面

工程结构

工程位于 SDK 内 1.SDK\ModuleDemo\WZTOE\3.HTTPServer\,核心文件如下:

3.HTTPServer/
├── Project/
│   └── Project.uvprojx       ← Keil 工程文件
└── USER/
    ├── main.c                ← 硬件初始化 + 网络配置 + HTTP Server 主循环
    ├── wiz_interface/
    │   ├── wiz_interface.c   ← PHY 检测 / 网络信息打印
    │   └── wiz_interface.h
    ├── httpServer/
    │   ├── httpServer.c      ← HTTP Server 状态机 / 网页内容定义
    │   ├── httpServer.h
    │   ├── httpUtil.c        ← CGI 请求处理(GET/POST 参数解析)
    │   └── httpUtil.h
    ├── eeprom/
    │   ├── eeprom.c          ← EEPROM 读写 / 网络配置持久化
    │   └── eeprom.h
    ├── uart/
    │   ├── bsp_uart.c        ← 调试串口 + printf 重定向
    │   └── bsp_uart.h
    ├── tim/
    │   └── bsp_tim.c/h       ← TIM3 1ms 定时器(供 HTTP/DHCP 超时)
    └── delay/
        └── delay.c/h          ← SysTick 毫秒延时

本例程相比 DHCP 章节的核心新增:HTTP Server 库的初始化、网页内容注册、CGI 回调处理以及 EEPROM 配置持久化。

步骤1:从 EEPROM 读取网络配置

文件:USER/main.c — 上电后首先检查 EEPROM 中是否有已保存的网络配置,有则加载,无则使用默认值。然后调用 network_init() 完成网络初始化(含 DHCP)。

check_eeprom_network_info(&default_net_info);
network_init(ethernet_buf, &default_net_info);

check_eeprom_network_info() 函数的作用是检查 EEPROM 中是否有网络地址信息,如果有则赋值给 default_net_info 结构体。函数内容如下:

uint8_t check_eeprom_network_info(wiz_NetInfo *net_info)
{
  wiz_NetInfo eeprom_net_info = {0};
  /*-----------------------------------------------------------------------------------*/
  if (ee_CheckDevice(EEPROM_DEV_ADDR) == 1)
  {
      /* No EEPROM detected */
      printf("No serial EEPROM detected!\r\n");
      return 0;
  }
  ee_ReadBytes((uint8_t *)&eeprom_net_info, 0, sizeof(eeprom_net_info));
  if (eeprom_net_info.mac[0] == 0x00 && eeprom_net_info.mac[1] == 0x08 && eeprom_net_info.mac[2] == 0xdc)
  {
      memcpy(net_info, &eeprom_net_info, sizeof(wiz_NetInfo));
      return 1;
  }
  return 0;
}

关键点:通过检查 MAC 地址前三字节(00:08:DC)判断 EEPROM 中是否存有有效配置。匹配则加载,否则返回 0 使用默认值。

步骤2:注册网页内容并初始化 HTTP Server

文件:USER/httpServer/httpServer.c + USER/main.c — 首先定义配置页面和配置成功页面的 HTML 内容,然后将网络信息格式化填充到页面模板中,最后注册网页内容并初始化 HTTP Server。

2.1 配置页面(index_page)

该页面包含一个 POST 表单,提交地址为 config.cgi,带有 JavaScript 表单验证功能。

#define index_page "<html>\n" \
"<head>\n" \
"    <title>W55MH32 Configuration Page</title>\n" \
"    <style>\n" \
"        body { font-family: Arial, sans-serif; margin: 20px; padding: 20px; background-color: #f4f4f9; }\n" \
"        h1 { text-align: center; color: #333; }\n" \
"        form { max-width: 400px; margin: auto; background: #ffffff; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); }\n" \
"        label { display: block; margin-bottom: 8px; font-weight: bold; }\n" \
"        input[type=text], input[type=submit] { width: 400px; padding: 8px; margin-bottom: 12px; border: 1px solid #ccc; border-radius: 4px; }\n" \
"        input[type=submit] { background-color: #4CAF50; color: white; border: none; cursor: pointer; }\n" \
"        input[type=submit]:hover { background-color: #45a049; }\n" \
"        input[readonly] { background-color: #e9ecef; color: #6c757d; border: 1px solid #ced4da; cursor: not-allowed; }\n" \
"        .error { color: red; font-size: 12px; margin-top: -10px; margin-bottom: 10px; }\n" \
"        input::placeholder { color: #aaa; font-style: italic; }\n" \
"    </style>\n" \
"    <script>\n" \
"        function validateForm(event) {\n" \
"            const ipPattern = /^(\\d{1,3}\\.){3}\\d{1,3}$/;\n" \
"            let isValid = true;\n" \
"            document.querySelectorAll('.error').forEach(e => e.textContent = '');\n" \
"            const fields = ['ip', 'subnet', 'gateway', 'dns'];\n" \
"            fields.forEach(field => {\n" \
"                const input = document.forms[0][field];\n" \
"                if (input.value.trim() === '') {\n" \
"                    input.placeholder = 'e.g., 192.168.1.1';\n" \
"                    document.getElementById(field + '-error').textContent = 'This field is required.';\n" \
"                    isValid = false;\n" \
"                } else if (!ipPattern.test(input.value)) {\n" \
"                    document.getElementById(field + '-error').textContent = 'Invalid IP address format.';\n" \
"                    isValid = false;\n" \
"                }\n" \
"            });\n" \
"            if (!isValid) { event.preventDefault(); }\n" \
"        }\n" \
"    </script>\n" \
"</head>\n" \
"<body>\n" \
"    <h1>W55MH32 Configuration Page</h1>\n" \
"    <form method=\"post\" action=\"config.cgi\" onsubmit=\"validateForm(event)\">\n" \
"        <label>MAC Address: </label><input type=\"text\" value=\"%s\" readonly><br>\n" \
"        <label>IP Address: </label><input type=\"text\" name=\"ip\" placeholder=\"e.g., 192.168.1.1\" value=\"%s\"><div id=\"ip-error\" class=\"error\"></div><br>\n" \
"        <label>Subnet Mask: </label><input type=\"text\" name=\"subnet\" placeholder=\"e.g., 255.255.255.0\" value=\"%s\"><div id=\"subnet-error\" class=\"error\"></div><br>\n" \
"        <label>Default Gateway: </label><input type=\"text\" name=\"gateway\" placeholder=\"e.g., 192.168.1.1\" value=\"%s\"><div id=\"gateway-error\" class=\"error\"></div><br>\n" \
"        <label>DNS Server: </label><input type=\"text\" name=\"dns\" placeholder=\"e.g., 8.8.8.8\" value=\"%s\"><div id=\"dns-error\" class=\"error\"></div><br>\n" \
"        <input type=\"submit\" value=\"Submit\">\n" \
"    </form>\n" \
"</body>\n" \
"</html>\n"

2.2 配置成功页面(CONFIG_SUCCESS_PAGE)

提交成功后显示的页面,带有 10 秒倒计时自动跳转到新 IP 地址。

#define CONFIG_SUCCESS_PAGE \
"<!DOCTYPE html>\n" \
"<html lang=\"en\">\n" \
"<head>\n" \
"    <meta charset=\"UTF-8\">\n" \
"    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" \
"    <title>Configuration Modification Succeeded</title>\n" \
"    <style>\n" \
"        body { font-family: Arial, sans-serif; text-align: center; padding-top: 100px; background-color: #f0f0f0; }\n" \
"        h1 { color: green; animation: fadeInOut 2s infinite; }\n" \
"        #countdown { font-size: 24px; margin-top: 20px; opacity: 0; animation: fadeIn 1s forwards; animation-delay: 1s; }\n" \
"        @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }\n" \
"    </style>\n" \
"</head>\n" \
"<body>\n" \
"    <h1>Configuration Modification Succeeded!</h1>\n" \
"    <p id=\"countdown\">Will redirect in 10 seconds. Please wait...</p>\n" \
"    <script>\n" \
"        let seconds = 10;\n" \
"        const countdownElement = document.getElementById('countdown');\n" \
"        const countdownInterval = setInterval(() => {\n" \
"            seconds--;\n" \
"            countdownElement.textContent = `Will redirect in ${seconds} seconds. Please wait...`;\n" \
"            if (seconds === 0) {\n" \
"                clearInterval(countdownInterval);\n" \
"                window.location.href = 'http://%d.%d.%d.%d/';\n" \
"            }\n" \
"        }, 1000);\n" \
"    </script>\n" \
"</body>\n" \
"</html>"

2.3 格式化页面并初始化

文件:USER/main.c — 将网络信息格式化为字符串,通过 sprintf 填充到 index_page 模板中的 %s 占位符,然后注册网页内容并初始化 HTTP Server。

printf("Please enter %d.%d.%d.%d in your browser to access the %s HTTP server\r\n",
       net_info.ip[0], net_info.ip[1], net_info.ip[2], net_info.ip[3], _WIZCHIP_ID_);
sprintf(mac, "%02X:%02X:%02X:%02X:%02X:%02X",
        net_info.mac[0], net_info.mac[1], net_info.mac[2],
        net_info.mac[3], net_info.mac[4], net_info.mac[5]);
sprintf(ip,  "%d.%d.%d.%d", net_info.ip[0], net_info.ip[1], net_info.ip[2], net_info.ip[3]);
sprintf(sn,  "%d.%d.%d.%d", net_info.sn[0], net_info.sn[1], net_info.sn[2], net_info.sn[3]);
sprintf(gw,  "%d.%d.%d.%d", net_info.gw[0], net_info.gw[1], net_info.gw[2], net_info.gw[3]);
sprintf(dns, "%d.%d.%d.%d", net_info.dns[0], net_info.dns[1], net_info.dns[2], net_info.dns[3]);
sprintf(page, (char *)index_page, mac, ip, sn, gw, dns);
reg_httpServer_webContent((uint8_t *)"index.html", (uint8_t *)page);         // 注册web内容
httpServer_init(http_tx_ethernet_buf, http_rx_ethernet_buf, 1, socknumlist); // 初始化HTTP Server

reg_httpServer_webContent() 注册 web 内容(HTML 页面或 JavaScript)。httpServer_init() 的四个参数分别是 HTTP 发送缓存、HTTP 接收缓存、使用的 SOCKET 数量以及对应的 SOCKET 列表。

步骤3:注册 HTTP 超时中断

文件:USER/tim/bsp_tim.c — HTTP Server 的超时判断需要一个 1 秒的累加计时器。在 TIM3 的 1ms 中断中累加,满 1 秒后同时调用 DHCP 和 HTTP Server 的超时处理函数。

/**
* @brief   1ms timer IRQ Handler
* @param   none
* @return  none
*/
void TIM3_IRQHandler(void)
{
  static uint32_t tim3_1ms_count = 0;
  if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
  {
      tim3_1ms_count++;
      if (tim3_1ms_count >= 1000)
      {
          DHCP_time_handler();
          httpServer_time_handler();
          tim3_1ms_count = 0;
      }
      TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
  }
}

步骤4:运行 HTTP Server

文件:USER/main.c — 在主循环中调用 httpServer_run() 驱动状态机。

while (1)
{
    httpServer_run(SOCKET_ID);
}

httpServer_run() 的逻辑跟 TCP Server 基本一致,运行一个状态机,根据 SOCKET 不同状态执行相应的 HTTP Server 处理:

void httpServer_run(uint8_t seqnum)
{
  uint8_t  s; // socket number
  uint16_t len;
  uint32_t gettime = 0;
#ifdef _HTTPSERVER_DEBUG_
  uint8_t destip[4] = { 0, };
  uint16_t destport = 0;
#endif
  http_request        = (st_http_request *)pHTTP_RX; // HTTP Request 结构体
  parsed_http_request = (st_http_request *)pHTTP_TX;
  // 获取 H/W socket number
  s = getHTTPSocketNum(seqnum);
  /* HTTP Service Start */
  switch (getSn_SR(s))
  {
  case SOCK_ESTABLISHED:
      // 中断清除
      if (getSn_IR(s) & Sn_IR_CON)
      {
          setSn_IR(s, Sn_IR_CON);
      }
      // HTTP 处理状态
      switch (HTTPSock_Status[seqnum].sock_status)
      {
      case STATE_HTTP_IDLE:
          if ((len = getSn_RX_RSR(s)) > 0)
          {
              if (len > DATA_BUF_SIZE) len = DATA_BUF_SIZE;
              len = recv(s, (uint8_t *)http_request, len);
              *(((uint8_t *)http_request) + len) = '\0';
              parse_http_request(parsed_http_request, (uint8_t *)http_request);
              // HTTP 'response' handler
              http_process_handler(s, parsed_http_request);
              gettime = get_httpServer_timecount();
              // 检查 TX socket buffer 是否发送完毕
              while (getSn_TX_FSR(s) != (getSn_TxMAX(s)))
              {
                  if ((get_httpServer_timecount() - gettime) > 3)
                  {
                      break;
                  }
              }
              if (HTTPSock_Status[seqnum].file_len > 0)
                  HTTPSock_Status[seqnum].sock_status = STATE_HTTP_RES_INPROC;
              else
                  HTTPSock_Status[seqnum].sock_status = STATE_HTTP_RES_DONE;
          }
          break;
      case STATE_HTTP_RES_INPROC:
          // 重复发送剩余的 HTTP 响应数据
          send_http_response_body(s, 0, http_response, 0, 0);
          if (HTTPSock_Status[seqnum].file_len == 0)
              HTTPSock_Status[seqnum].sock_status = STATE_HTTP_RES_DONE;
          break;
      case STATE_HTTP_RES_DONE:
          // Socket file info 结构体重新初始化
          HTTPSock_Status[seqnum].file_len    = 0;
          HTTPSock_Status[seqnum].file_offset = 0;
          HTTPSock_Status[seqnum].file_start  = 0;
          HTTPSock_Status[seqnum].sock_status = STATE_HTTP_IDLE;
          http_disconnect(s);
          break;
      default:
          break;
      }
      break;
  case SOCK_CLOSE_WAIT:
      disconnect(s);
      break;
  case SOCK_CLOSED:
      if (reboot_flag)
      {
          NVIC_SystemReset();
      }
      if (socket(s, Sn_MR_TCP, HTTP_SERVER_PORT, 0x00) == s) /* 重新初始化 socket */
      {
      }
      break;
  case SOCK_INIT:
      listen(s);
      break;
  case SOCK_LISTEN:
      break;
  default:
      break;
  } // end of switch
}

状态机说明

  • SOCK_LISTEN → 等待客户端连接
  • SOCK_ESTABLISHED → 收到请求后解析并处理响应(IDLE → RES_INPROC → RES_DONE)
  • SOCK_CLOSED → 检查 reboot_flag 决定是否重启,然后重新打开 Socket 监听

步骤5:CGI 请求处理

文件:USER/httpServer/httpUtil.c — POST 方式的 CGI 请求在 predefined_set_cgi_processor() 函数中处理。当 URI 为 config.cgi 时,解析表单参数、更新网络配置、写入 EEPROM 并设置重启标志。

uint8_t predefined_set_cgi_processor(uint8_t *uri_name, uint8_t *uri, uint8_t *buf, uint16_t *len)
{
  if (strcmp((const char *)uri_name, "config.cgi") == 0)
  {
      uint8_t    *param;
      wiz_NetInfo new_net_info = {0};
      wizchip_getnetinfo(&new_net_info);
      param = get_http_param_value((char *)uri, "ip");        // 获取IP地址
      parse_ip((char *)param, new_net_info.ip);               // 更新IP地址
      param = get_http_param_value((char *)uri, "subnet");    // 获取子网掩码
      parse_ip((char *)param, new_net_info.sn);               // 更新子网掩码
      param = get_http_param_value((char *)uri, "gateway");   // 获取默认网关
      parse_ip((char *)param, new_net_info.gw);               // 更新默认网关
      param = get_http_param_value((char *)uri, "dns");       // 获取DNS地址
      parse_ip((char *)param, new_net_info.dns);              // 更新DNS地址
      new_net_info.dhcp = NETINFO_STATIC;
      ee_WriteBytes((uint8_t *)&new_net_info, 0, sizeof(wiz_NetInfo));
      reboot_flag = 1;
      *len = sprintf((char *)buf, (char *)CONFIG_SUCCESS_PAGE,
                     new_net_info.ip[0], new_net_info.ip[1],
                     new_net_info.ip[2], new_net_info.ip[3]);
      return 1;
  }
  return 0;
}

处理流程

get_http_param_value() 从 POST 请求体中提取参数值,parse_ip() 将字符串转换为 IP 数组。新配置写入 EEPROM 后设置 reboot_flag = 1,同时返回 CONFIG_SUCCESS_PAGE 作为响应体(包含新 IP 用于倒计时跳转)。

步骤6:重启设备应用新配置

在 httpServer_run() 函数中,当 SOCKET 处于 SOCK_CLOSED 状态时(即上次请求已处理完毕),再进行复位操作,避免客户端请求后 W55MH32 未响应就重启导致超时。

case SOCK_CLOSED:
    if (reboot_flag)
    {
        NVIC_SystemReset();
    }

为什么选在 SOCK_CLOSED 重启

如果在响应尚未发送完毕时立即重启,客户端会因连接异常断开而出现请求超时。选择在 SOCK_CLOSED 状态复位,意味着本次 HTTP 请求-响应周期已完全结束,连接已正常关闭,此时重启不会影响客户端体验,浏览器还能根据配置成功页面的倒计时自动跳转到新地址。

运行验证

烧录例程运行后,首先进行 PHY 链路检测,然后通过 DHCP 获取网络地址并打印,最后 HTTP Server 开始监听。打开 WIZ UartTool V1.0,连接 DEBUG USB 对应 COM 口(115200 / 8N1),预期串口输出如下:

W55MH32 HTTP Server example
PHY link
The current Mbtis speed : 100Mbps
The current Duplex Mode : Full-Duplex
DHCP running
DHCP success!
====================================================================================================
 W55MH32 network configuration : DHCP

 MAC         : 00:08:DC:00:0E:9A
 IP          : 192.168.1.6
 Subnet Mask : 255.255.255.0
 Gateway     : 192.168.1.1
 DNS         : 192.168.1.1
====================================================================================================

Please enter 192. 168. 1. 6 in your browser to access the W55MH32 HTTP server
> HTTPSocket[0] : CLOSED
> HTTPSocket[0] : OPEN

请注意

测试实例需要 PC 端和 W55MH32 处于同一网段。

W55MH32 串口输出 — HTTP 服务器初始化(PHY 链路 + 网络地址 + HTTP Socket 监听)

打开浏览器,输入 W55MH32 的 IP 地址(如 192.168.1.6)进行访问,即可看到配置页面。

浏览器访问 192.168.1.6 — W55MH32 Configuration Page(IP 192.168.1.6 / DNS 192.168.8.1.1)

将 IP 地址改为 192.168.1.33,DNS 改为 114.114.114.114,点击 Submit 按钮。等待 W55MH32 重启后,浏览器会自动跳转至新地址。

浏览器访问 192.168.1.33 — W55MH32 Configuration Page(IP 已改为 192.168.1.33 / DNS 已改为 114.114.114.114)

常见问题

Q: HTTP 协议的无状态性是什么意思

HTTP 本身不保存请求之间的状态,每次请求都是独立的,服务器不会记录上一次请求的信息。如果需要保持状态(如用户登录),可以通过 Cookie、Session 等机制实现。W55MH32 作为 HTTP Server 时,每次请求处理完毕后即断开连接。

Q: GET 和 POST 方法如何选择

GET 用于从服务器获取资源,参数通过 URL 查询字符串传递,长度受限且明文显示,不适合敏感信息。POST 用于向服务器提交数据,数据放在请求体中,体积无明显限制且相对安全。本例程中修改网络配置使用 POST 方式提交到 config.cgi,避免参数暴露在 URL 中。

Q: 修改网络配置后为什么要重启设备

网络地址信息写入 EEPROM 后,需要重新初始化网络协议栈才能使新配置生效。本例程通过设置 reboot_flag 标志位,在 httpServer_run() 检测到 SOCK_CLOSED 状态(即上一次请求处理完毕)时调用 NVIC_SystemReset() 复位设备,避免客户端请求未响应就重启导致超时。

Q: 为什么重启时机要选在 SOCK_CLOSED 状态

如果在响应尚未发送完毕时立即重启,客户端会因连接异常断开而出现请求超时。选择在 SOCK_CLOSED 状态复位,意味着本次 HTTP 请求-响应周期已完全结束,连接已正常关闭,此时重启不会影响客户端体验,浏览器还能根据配置成功页面的倒计时自动跳转到新地址。

Q: httpServer_init 的四个参数分别是什么

四个参数依次为:HTTP 发送缓存(http_tx_ethernet_buf)、HTTP 接收缓存(http_rx_ethernet_buf)、使用的 SOCKET 数量(如 1)、以及对应的 SOCKET 列表(socknumlist)。注册网页内容则通过 reg_httpServer_webContent() 完成,可以是 HTML 页面或 JavaScript 代码。

总结

本文实现了 W55MH32 通过 HTTP Server 修改网络配置的完整流程:

  • 协议基础:HTTP 是基于 TCP/IP 的应用层协议,采用请求-响应模型,具有无状态、无连接的特点
  • 请求方法:GET 用于获取资源(参数在 URL),POST 用于提交数据(参数在请求体),本例程使用 POST 修改网络配置
  • 响应结构:响应由状态行、响应头、响应体三部分组成,响应头与响应体之间用空行分隔
  • 实现步骤:EEPROM 读取配置 → 注册网页与初始化 HTTP Server → 注册超时中断 → 运行状态机 → CGI 处理 POST 提交 → 重启生效
  • 配置持久化:新网络参数写入 EEPROM,重启后通过 check_eeprom_network_info() 读取,实现断电不丢失
  • 安全重启:在 SOCK_CLOSED 状态复位设备,确保响应发送完毕,浏览器可自动跳转新地址

下载本章例程

我们提供完整的工程文件以及配套开发板,方便你随时测试,快速完成产品开发:

开发环境: Keil MDK5 配套开发板

Andy

W5500 技术支持专家