hi

全部例程

WIZnet W55MH32 多功能测试固件

W55MH32

更新于 2026年1月8日

本篇文章将详细介绍W55MH32 芯片用户配置界面的实现方法,搭配W55MH32LEVB,并结合实战例程,讲解如何以W55MH32 作为 HTTP 服务器、PC 端作为 HTTP 客户端,通过网页配置界面完成外设功能控制、SD 卡读写及网络参数配置等操作。

该例程用到的其他网络协议,例如DHCP, 请参考相关章节。有关 W55MH32 的初始化过程,请参考Network install,这里将不再赘述。

Web网页简介

Web(World Wide Web,万维网)是一种基于超文本和HTTP的全球性、动态交互的、跨平台的分布式图形信息系统。它建立在Internet之上,为用户提供了一个图形化、易于访问的界面,用于查找和浏览信息。

Web页面的基本构成

1.HTML(超文本标记语言)

作用:定义网页的结构和内容。

内容:

  • 结构标签:如 <html>、<head>、<body>。
  • 内容标签:如 <h1>、<p>、<img>、<a>。
  • 表单标签:如 <form>、<input>、<button>。

2.CSS(层叠样式表)

作用:控制网页的样式和布局。

内容:

  • 字体设置:如 font-family、font-size。
  • 颜色设置:如 color、background-color。
  • 布局设计:如 margin、padding、display、flex。
  • 响应式设计:如媒体查询(@media)。

3.JavaScript(脚本语言)

作用:增加网页的交互性和动态功能。

应用:

  • 表单验证。
  • 动画效果。
  • 与服务器交互(如通过 AJAX 请求)。
  • 处理用户事件(如点击、悬停)。

4.Meta 信息

作用:提供页面的元数据,通常包含在 <head> 中。

内容:

  • 网页标题:<title>。
  • 字符集:<meta charset="UTF-8">。
  • SEO 信息:如<meta name="description" content="描述">。
  • 设备适配:如 <meta name="viewport" content="width=device-width, initial-scale=1.0>"。

示例:

<!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页面交互

1.HTTP 请求页面

描述:客户端通过 HTTP 协议向服务器发送请求,服务器处理后返回响应。

特点:

  • 最基础的交互方式。
  • 包括常见的 HTTP 方法:GET、POST、PUT、DELETE 等。

示例:

  • GET 请求:浏览器访问网页,获取静态资源(HTML、CSS、JavaScript 等)。
  • POST 请求:提交表单数据。

2.表单提交

描述:通过 HTML 表单向服务器提交数据。

特点:

  • 表单数据会被编码后随请求发送。
  • 可使用 GET 或 POST 方法。

示例:

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

3.AJAX(Asynchronous JavaScript and XML)

描述:使用 JavaScript 在后台与服务器通信,更新部分页面内容而无需刷新整个页面。

特点:

  • 提高用户体验,减少页面加载时间。
  • 现代开发中多用 JSON 代替 XML。

示例:

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

Web服务器响应处理

1.直接响应

定义: 服务器直接处理请求,返回静态资源或简单的动态内容,而不调用外部脚本或程序。

特点

  • 高效:直接处理请求,无需额外调用外部程序,适合静态内容。

适用场景:

  • 静态资源(HTML、CSS、JavaScript、图像等)的分发。
  • 轻量级动态内容生成。

工作流程

  1. 客户端发送 HTTP 请求。
  2. 服务器解析请求 URL,查找相应的资源(如文件路径)。
  3. 直接读取资源内容并返回给客户端,附加适当的 HTTP 响应头。

2.CGI 响应

定义: 服务器通过 CGI(Common Gateway Interface)调用外部程序或脚本,处理客户端请求并生成动态响应内容。

特点

  • 灵活性: 可以动态生成内容,支持复杂逻辑。

适用场景:

  • 动态内容生成(如用户登录、数据查询)。
  • 与数据库交互或其他后台服务的复杂逻辑处理。

工作流程

  1. 客户端发送 HTTP 请求。
  2. 服务器解析请求并将请求数据(如 URL 参数或表单数据)传递给 CGI 程序。
  3. CGI 程序处理请求,生成响应内容并返回给服务器。
  4. CGI 程序生成的内容包装为 HTTP 响应发送给客户端。

实现过程

接下来,我们看看如何通过W55MH32用户配置页面实现操作和配置W55MH32。

首先需要编写网页内容,这里我们写了W55MH32用户配置的显示界面以及异常处理的提示内容,如下所示:

#ifndef _WEBPAGE_H_
#define _WEBPAGE_H_

/*************************************************************************************
 * HTML Pages (web pages)
 *************************************************************************************/

#define HTML_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>W55MH32 用户配置界面</title>\n"                                                                                                                                                             \
  "    <link rel="icon" href="data:,">\n"                                                                                                                                                             \
  "    <!-- CSS -->\n"                                                                                                                                                                                    \
  "    <style>\n"                                                                                                                                                                                                 \
  "        body {\n"                                                                                                                                                                                                  \
  "            font-family: Arial, sans-serif;\n"                                                                                                                                                         \
  "            text-align: center;\n"                                                                                                                                                                     \
  "            margin: 20px;\n"                                                                                                                                                                           \
  "        }\n"                                                                                                                                                                                                   \
  "        .container {\n"                                                                                                                                                                                \
  "            width: 80%;\n"                                                                                                                                                                             \
  "            margin: auto;\n"                                                                                                                                                                           \
  "            border: 1px solid #ccc;\n"                                                                                                                                                                 \
  "            padding: 20px;\n"                                                                                                                                                                          \
  "            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);\n"                                                                                                                                                \
  "        }\n"                                                                                                                                                                                                   \
  "        .section {\n"                                                                                                                                                                                  \
  "            margin: 20px 0;\n"                                                                                                                                                                         \
  "            padding: 10px;\n"                                                                                                                                                                          \
  "            border: 1px solid #ccc;\n"                                                                                                                                                                 \
  "            height: auto;\n"                                                                                                                                                                           \
  "            display: flex;\n"                                                                                                                                                                          \
  "            flex-direction: column;\n"                                                                                                                                                                 \
  "            justify-content: flex-start;\n"                                                                                                                                                            \
  "            align-items: center;\n"                                                                                                                                                                    \
  "        }\n"                                                                                                                                                                                                   \
  "        button {\n"                                                                                                                                                                                    \
  "            background-color: #4CAF50;\n"                                                                                                                                                              \
  "            color: white;\n"                                                                                                                                                                           \
  "            border: none;\n"                                                                                                                                                                           \
  "            padding: 8px 16px;\n"                                                                                                                                                                      \
  "            font-size: 16px;\n"                                                                                                                                                                        \
  "            cursor: pointer;\n"                                                                                                                                                                        \
  "            border-radius: 5px;\n"                                                                                                                                                                     \
  "            margin: 5px;\n"                                                                                                                                                                            \
  "        }\n"                                                                                                                                                                                                   \
  "        button:hover {\n"                                                                                                                                                                              \
  "            background-color: #45a049;\n"                                                                                                                                                              \
  "        }\n"                                                                                                                                                                                                   \
  "        .textbox {\n"                                                                                                                                                                                  \
  "            width: 90%;\n"                                                                                                                                                                             \
  "            height: 300px;\n"                                                                                                                                                                          \
  "            margin: 10px 0;\n"                                                                                                                                                                         \
  "            display: block;\n"                                                                                                                                                                         \
  "            border: 1px solid #ccc;\n"                                                                                                                                                                 \
  "            padding: 10px;\n"                                                                                                                                                                          \
  "            resize: none;\n"                                                                                                                                                                           \
  "            box-sizing: border-box;\n"                                                                                                                                                                 \
  "            overflow-y: auto;\n"                                                                                                                                                                       \
  "        }\n"                                                                                                                                                                                                   \
  "        .input {\n"                                                                                                                                                                                    \
  "            width: 90%;\n"                                                                                                                                                                             \
  "            padding: 10px;\n"                                                                                                                                                                          \
  "            margin: 10px 0;\n"                                                                                                                                                                         \
  "            border: 1px solid #ccc;\n"                                                                                                                                                                 \
  "            box-sizing: border-box;\n"                                                                                                                                                                 \
  "        }\n"                                                                                                                                                                                                   \
  "        .row {\n"                                                                                                                                                                                      \
  "            display: flex;\n"                                                                                                                                                                          \
  "            justify-content: space-between;\n"                                                                                                                                                         \
  "            align-items: flex-start;\n"                                                                                                                                                                \
  "            gap: 10px;\n"                                                                                                                                                                              \
  "        }\n"                                                                                                                                                                                                   \
  "        .column {\n"                                                                                                                                                                                   \
  "            width: 30%;\n"                                                                                                                                                                             \
  "            height: 450px;\n"                                                                                                                                                                          \
  "        }\n"                                                                                                                                                                                                   \
  "        .info-section {\n"                                                                                                                                                                             \
  "            display: flex;\n"                                                                                                                                                                          \
  "            justify-content: space-between;\n"                                                                                                                                                         \
  "            align-items: center;\n"                                                                                                                                                                    \
  "            margin-bottom: 10px;\n"                                                                                                                                                                    \
  "        }\n"                                                                                                                                                                                                   \
  "        .info {\n"                                                                                                                                                                                     \
  "            font-size: 16px;\n"                                                                                                                                                                        \
  "            margin: 0 5px;\n"                                                                                                                                                                          \
  "        }\n"                                                                                                                                                                                                   \
  "        .button-container {\n"                                                                                                                                                                         \
  "            display: flex;\n"                                                                                                                                                                          \
  "            justify-content: space-evenly;\n"                                                                                                                                                          \
  "            align-items: center;\n"                                                                                                                                                                    \
  "            flex-wrap: wrap;\n"                                                                                                                                                                        \
  "            gap: 10px;\n"                                                                                                                                                                              \
  "        }\n"                                                                                                                                                                                                   \
  "    </style>\n"                                                                                                                                                                                        \
  "</head>\n"                                                                                                                                                                                                 \
  "<!-- body -->\n"                                                                                                                                                                                       \
  "<body onload='page_load()'>\n"                                                                                                                                                                         \
  "    <div class="container">\n"                                                                                                                                                                       \
  "        <h1>W55MH32 用户配置界面</h1>\n"                                                                                                                                                               \
  "        <p id="current-time"></p>\n"                                                                                                                                                                 \
  "        <div class="section">\n"                                                                                                                                                                     \
  "            <div class="info-section">\n"                                                                                                                                                            \
  "                <p class="info">当前温度:<label id="temperature">NULL</label>°C</p>\n"                                                                                                            \
  "                <p class="info">当前湿度:<label id="humidity">NULL</label>%RH</p>\n"                                                                                                              \
  "                <p class="info">按键次数统计:<label id="button_cnt">0</label>次</p>\n"                                                                                                            \
  "            </div>\n"                                                                                                                                                                                  \
  "            <div class="button-container">\n"                                                                                                                                                        \
  "                <button val='1' name='led' onclick="set_io_state(this)">LED开</button>\n"                                                                                                            \
  "                <button val='0' name='led' onclick="set_io_state(this)">LED关</button>\n"                                                                                                            \
  "                <button val='1' name='beep' onclick="set_io_state(this)">蜂鸣器开</button>\n"                                                                                                        \
  "                <button val='0' name='beep' onclick="set_io_state(this)">蜂鸣器关</button>\n"                                                                                                        \
  "                <button onclick="check_eeprom()">测试eeprom</button>\n"                                                                                                        \
  "            </div>\n"                                                                                                                                                                                  \
  "        </div>\n"                                                                                                                                                                                      \
  "        <div class="row">\n"                                                                                                                                                                         \
  "            <div class="column section">\n"                                                                                                                                                          \
  "                <p>SD卡</p>\n"                                                                                                                                                                         \
  "                <textarea class="textbox" readonly id="sd-textbox" placeholder="SD卡内容显示"></textarea>\n"                                                                                     \
  "                <button onclick="readContent()">读取内容</button>\n"                                                                                                                                 \
  "                <button onclick="writeContent()">写入内容</button>\n"                                                                                                                                \
  "                <input type="file" id="fileInput" onchange="choose_file()" accept=".txt" style="display: none;" />\n"                                                                        \
  "            </div>\n"                                                                                                                                                                                  \
  "            <div class="column section">\n"                                                                                                                                                          \
  "                <p>网络配置</p>\n"                                                                                                                                                                     \
  "                <select class="input" name="network-mode" id="network-mode">"                                                                                                                    \
  "                  <option value="2" selected>DHCP</option>"                                                                                                                                          \
  "                  <option value="1">静态配置</option>"                                                                                                                                               \
  "                </select>"                                                                                                                                                                             \
  "                <input class="input" type="text" id="mac-address" disabled>\n"                                                                                                                   \
  "                <input class="input" type="text" id="ip-address" placeholder="IP地址">\n"                                                                                                      \
  "                <input class="input" type="text" id="subnet-mask" placeholder="子网掩码">\n"                                                                                                   \
  "                <input class="input" type="text" id="default-gateway" placeholder="默认网关">\n"                                                                                               \
  "                <input class="input" type="text" id="dns" placeholder="DNS">\n"                                                                                                                \
  "                <button onclick="saveConfiguration()">保存并配置</button>\n"                                                                                                                         \
  "            </div>\n"                                                                                                                                                                                  \
  "            <div class="column section">\n"                                                                                                                                                          \
  "                <p>USB串口</p>\n"                                                                                                                                                                      \
  "                <textarea class="textbox" readonly id="usb-textbox" placeholder="USB串口显示"></textarea>\n"                                                                                     \
  "                <input class="input" type="text" id="usb-input" placeholder="输入消息">\n"                                                                                                     \
  "                <button onclick="sendMessage()">发送消息</button>\n"                                                                                                                                 \
  "            </div>\n"                                                                                                                                                                                  \
  "        </div>\n"                                                                                                                                                                                      \
  "    </div>\n"                                                                                                                                                                                          \
  "    <script>\n"                                                                                                                                                                                        \
  "       <!-- AJAX -->\n"                                                                                                                                                                                \
  "       function AJAX(a,e){\n"                                                                                                                                                                            \
  "       	var c=d();\n"                                                                                                                                                                                    \
  "       	c.onreadystatechange=b;\n"                                                                                                                                                                       \
  "       	function d(){\n"                                                                                                                                                                                 \
  "       		if(window.XMLHttpRequest){\n"                                                                                                                                                                   \
  "       			return new XMLHttpRequest()\n"                                                                                                                                                                 \
  "       		}\n"                                                                                                                                                                                            \
  "       		else{\n"                                                                                                                                                                                        \
  "       			if(window.ActiveXObject){\n"                                                                                                                                                                   \
  "       				return new ActiveXObject("Microsoft.XMLHTTP")\n"                                                                                                                                            \
  "       			}\t\n"                                                                                                                                                                                          \
  "       		}\n"                                                                                                                                                                                            \
  "       	}\n"                                                                                                                                                                                             \
  "       	function b(){\n"                                                                                                                                                                                 \
  "       		if(c.readyState==4){\n"                                                                                                                                                                         \
  "       			if(c.status==200){\n"                                                                                                                                                                          \
  "       				if(e){\n"                                                                                                                                                                                     \
  "       					e(c.responseText)\n"                                                                                                                                                                         \
  "       				}\n"                                                                                                                                                                                          \
  "       			}\n"                                                                                                                                                                                           \
  "       		}\n"                                                                                                                                                                                            \
  "       	}\n"                                                                                                                                                                                             \
  "       	this.doGet=function(){\n"                                                                                                                                                                        \
  "       		c.open("GET",a,true);\n"                                                                                                                                                                      \
  "       		c.send(null)\n"                                                                                                                                                                                 \
  "       	};\n"                                                                                                                                                                                            \
  "       	this.doPost=function(f){\n"                                                                                                                                                                      \
  "       		c.open("POST",a,true);\n"                                                                                                                                                                     \
  "       		c.setRequestHeader("Content-Type","application/x-www-form-urlencoded");\n"                                                                                                                  \
  "       		c.setRequestHeader("ISAJAX","yes");\n"                                                                                                                                                      \
  "       		c.send(f)\n"                                                                                                                                                                                    \
  "       	}\n"                                                                                                                                                                                             \
  "       }\n"                                                                                                                                                                                              \
  "       function $(a){\n"                                                                                                                                                                                 \
  "       	return document.getElementById(a)\n"                                                                                                                                                             \
  "       }\n"                                                                                                                                                                                              \
  "       function $$(a){\n"                                                                                                                                                                                \
  "       	return document.getElementsByName(a)\n"                                                                                                                                                          \
  "       }\n"                                                                                                                                                                                              \
  "       function $$_ie(a,c){if(!a){\n"                                                                                                                                                                    \
  "       	a="*"\n"                                                                                                                                                                                       \
  "       }\n"                                                                                                                                                                                              \
  "       var b=document.getElementsByTagName(a);\n"                                                                                                                                                        \
  "       var e=[];\n"                                                                                                                                                                                      \
  "       for(var d=0;d<b.length;d++){\n"                                                                                                                                                                   \
  "       	att=b[d].getAttribute("name");\n"                                                                                                                                                              \
  "       		if(att==c){\n"                                                                                                                                                                                  \
  "       			e.push(b[d])\n"                                                                                                                                                                                \
  "       		}\n"                                                                                                                                                                                            \
  "       	}\n"                                                                                                                                                                                             \
  "       	return e\n"                                                                                                                                                                                      \
  "       }\n"                                                                                                                                                                                              \
  "       <!-- led_beep_js -->\n"                                                                                                                                                                         \
  "       function set_io_state(o){\n"                                                                                                                                                                    \
  "       	var name=o.attributes['name'].value;\n"                                                                                                                                                        \
  "       	var val=o.attributes['val'].value;\n"                                                                                                                                                          \
  "       	dout=new AJAX('set_io_state.cgi', function(t){try{eval(t);}catch(e){alert(e);}});\n"                                                                                                           \
  "       	dout.doPost('name='+name+'&val='+val);\n"                                                                                                                                                      \
  "       }\n"                                                                                                                                                                                            \
  "       <!-- eeprom -->\n"\
  "       function check_eeprom(){\n"\
  "       		ajax = new AJAX('check_eeprom.cgi', function (t) { try { eval(t); } catch (e) { alert(e); } });\n"                                                                                  \
  "       		ajax.doGet();\n"                                                                                                                                                                       \
  "           }\n"\
  "       <!-- netinfo_js -->\n"                                                                                                                                                                          \
  "       function get_netinfo(){\n"                                                                                                                                                                      \
  "       	var oUpdate;\n"                                                                                                                                                                                \
  "       	setTimeout(function(){\n"                                                                                                                                                                      \
  "       	oUpdate=new AJAX('get_netinfo.cgi',function(t){\n"                                                                                                                                             \
  "       		try{eval(t);}catch(e){alert(e);}\n"                                                                                                                                                           \
  "       	});\n"                                                                                                                                                                                         \
  "       	oUpdate.doGet();},500);\n"                                                                                                                                                                     \
  "       }\n"                                                                                                                                                                                            \
  "       function set_netinfo(){\n"                                                                                                                                                                      \
  "         const mode = document.getElementById('network-mode').value;\n"                                                                                                                                \
  "         const mac = document.getElementById('mac-address').value;\n"                                                                                                                                  \
  "       	const ip = document.getElementById('ip-address').value;\n"                                                                                                                                     \
  "       	const subnet = document.getElementById('subnet-mask').value;\n"                                                                                                                                \
  "       	const gateway = document.getElementById('default-gateway').value;\n"                                                                                                                           \
  "       	const dns = document.getElementById('dns').value;\n"                                                                                                                                           \
  "       	update_netinfo=new AJAX('set_netinfo.cgi',function(t){try{eval(t);}catch(e){alert(e);}});\n"                                                                                                   \
  "       	update_netinfo.doPost('mode='+mode+'&ip='+ip+'&sn='+subnet+'&gw='+gateway+'&dns='+dns);\n"                                                                                                     \
  "       }\n"                                                                                                                                                                                            \
  "       function get_netinfo_callback(o){\n"                                                                                                                                                            \
  "         $('network-mode').value=o.mode;\n"                                                                                                                                                            \
  "         $('mac-address').value=o.mac;\n"                                                                                                                                                              \
  "       	$('ip-address').value=o.ip;\n"                                                                                                                                                                 \
  "       	$('default-gateway').value=o.gw;\n"                                                                                                                                                            \
  "       	$('subnet-mask').value=o.sn;\n"                                                                                                                                                                \
  "       	$('dns').value=o.dns;\n"                                                                                                                                                                       \
  "       }\n"                                                                                                                                                                                            \
  "       <!-- update_page_js -->\n"                                                                                                                                                                      \
  "       function update_page(){\n"                                                                                                                                                                      \
  "       	setInterval(function () {\n"                                                                                                                                                                   \
  "       		update_page = new AJAX('get_update_page.cgi', function (t) { try { eval(t); } catch (e) { alert(e); } });\n"                                                                                  \
  "       		update_page.doGet();\n"                                                                                                                                                                       \
  "       	}, 1000);\n"                                                                                                                                                                                   \
  "       }\n"                                                                                                                                                                                            \
  "       function update_page_callback(o){\n"                                                                                                                                                            \
  "           $('temperature').innerHTML=o.temperature;\n"                                                                                                                                                \
  "       	  $('humidity').innerHTML=o.humidity;\n"                                                                                                                                                         \
  "       	  $('button_cnt').innerHTML=o.button_cnt;\n"                                                                                                                                                     \
  "           if(o.usbdata){\n"                                                                                                                                                                           \
  "               $('usb-textbox').value=o.usbdata+$('usb-textbox').value;\n"                                                                                                                             \
  "           }\n"                                                                                                                                                                                        \
  "           if(o.usb_conn_flag==0){\n"\
  "               document.getElementById('usb-input').disabled=true\n"\
  "               $('usb-input').placeholder="USB未连接"\n"\
  "           }\n"\
  "           else{\n"\
  "               document.getElementById('usb-input').disabled=false\n"\
  "               $('usb-input').placeholder="输入消息"\n"\
  "           }\n"\
  "       }\n"                                                                                                                                                                                            \
  "       <!-- web_usb_js -->\n"                                                                                                                                                                          \
  "       function web_send_usb_data(){\n"                                                                                                                                                                \
  "       	dout=new AJAX('web_send_usb_data.cgi', function(t){try{eval(t);}catch(e){alert(e);}});\n"                                                                                                      \
  "       	dout.doPost('data='+$('usb-input').value);\n"                                                                                                                                                  \
  "       }\n"                                                                                                                                                                                            \
  "       <!-- sd_js -->\n"                                                                                                                                                                               \
  "	    function get_sd_file_name(){\n"                                                                                                                                                                   \
  " 	    		$('sd-textbox').value='';\n"                                                                                                                                                                 \
  "	    		dout=new AJAX('get_sd.cgi', function(t){try{eval(t);}catch(e){alert(e);}});\n"                                                                                                                  \
  "	    		dout.doGet();\n"                                                                                                                                                                                \
  "	    	}\n"                                                                                                                                                                                             \
  "	    function choose_file(){ \n"                                                                                                                                                                       \
  " 	    	file = $('fileInput').files[0];\n"                                                                                                                                                              \
  "	    	dout=new AJAX('put_sd.cgi', function(t){try{eval(t);}catch(e){alert(e);}});\n"                                                                                                                   \
  " 	    	if(file){\n"                                                                                                                                                                                    \
  " 	    		const reader = new FileReader();\n"                                                                                                                                                            \
  " 	    		reader.onload = function(e){\n"                                                                                                                                                                \
  "  	    		let content = e.target.result;\n"                                                                                                                                                             \
  "               if(content.length<100){\n"                                                                                                                                                              \
  "  	    		    dout.doPost("filename="+file.name+"&filelen="+content.length+"&filedata="+content);\n"                                                                                              \
  "               }\n"                                                                                                                                                                                    \
  "               else{\n"                                                                                                                                                                                \
  "                   alert('文件过大!');\n"                                                                                                                                                              \
  "               }\n"                                                                                                                                                                                    \
  "  	    		console.log("filename="+file.name+"&filelen='"+content.length+"'&filedata="+content);\n"                                                                                                \
  "  	    		console.log('filedata:'+content);\n"                                                                                                                                                          \
  "  	    		console.log('filename:'+file.name);\n"                                                                                                                                                        \
  "  	    		console.log('filelen:'+content.length);\n"                                                                                                                                                    \
  "  	    	};\n"                                                                                                                                                                                          \
  "  	    	reader.readAsText(file);\n"                                                                                                                                                                    \
  "	    	}\n"                                                                                                                                                                                             \
  "	    	else{\n"                                                                                                                                                                                         \
  "	    		alert('请选择文件');\n"                                                                                                                                                                       \
  "	    	}\n"                                                                                                                                                                                             \
  "	    }\n"                                                                                                                                                                                              \
  "       <!-- update_time_js -->\n"                                                                                                                                                                      \
  "       function updateTime() {\n"                                                                                                                                                                      \
  "           const now = new Date();\n"                                                                                                                                                                  \
  "           const formattedTime = now.toLocaleString();\n"                                                                                                                                              \
  "           document.getElementById('current-time').innerText = `当前时间: ${formattedTime}`;\n"                                                                                                        \
  "       }\n"                                                                                                                                                                                            \
  "       setInterval(updateTime, 1000);\n"                                                                                                                                                               \
  "       updateTime();\n"                                                                                                                                                                                \
  "       function writeContent() {\n"                                                                                                                                                                    \
  "           document.getElementById('fileInput').value="";\n"                                                                                                                                         \
  "           document.getElementById('fileInput').click();\n"                                                                                                                                            \
  "       }\n"                                                                                                                                                                                            \
  "       function readContent() {\n"                                                                                                                                                                     \
  "           get_sd_file_name();\n"                                                                                                                                                                      \
  "       }\n"                                                                                                                                                                                            \
  "       function isValidIPv4(ip) {\n"                                                                                                                                                                   \
  "           const regex = /^(25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)$/;\n" \
  "           return regex.test(ip);\n"                                                                                                                                                                   \
  "       }\n"                                                                                                                                                                                            \
  "       function saveConfiguration() {\n"                                                                                                                                                               \
  "           const ip = document.getElementById('ip-address').value;\n"                                                                                                                                  \
  "           const subnet = document.getElementById('subnet-mask').value;\n"                                                                                                                             \
  "           const gateway = document.getElementById('default-gateway').value;\n"                                                                                                                        \
  "           const dns = document.getElementById('dns').value;\n"                                                                                                                                        \
  "           if (!isValidIPv4(ip)) {\n"                                                                                                                                                                  \
  "               alert('IP地址格式不正确!');\n"                                                                                                                                                         \
  "               return;\n"                                                                                                                                                                              \
  "           }\n"                                                                                                                                                                                        \
  "           if (!isValidIPv4(subnet)) {\n"                                                                                                                                                              \
  "               alert('子网掩码格式不正确!');\n"                                                                                                                                                       \
  "               return;\n"                                                                                                                                                                              \
  "           }\n"                                                                                                                                                                                        \
  "           if (!isValidIPv4(gateway)) {\n"                                                                                                                                                             \
  "               alert('默认网关格式不正确!');\n"                                                                                                                                                       \
  "               return;\n"                                                                                                                                                                              \
  "           }\n"                                                                                                                                                                                        \
  "           if (!isValidIPv4(dns)) {\n"                                                                                                                                                                 \
  "               alert('DNS地址格式不正确!');\n"                                                                                                                                                        \
  "               return;\n"                                                                                                                                                                              \
  "           }\n"                                                                                                                                                                                        \
  "			set_netinfo();\n"                                                                                                                                                                                   \
  "       }\n"                                                                                                                                                                                            \
  "       function sendMessage() {\n"                                                                                                                                                                     \
  "           const input = document.getElementById('usb-input');\n"                                                                                                                                      \
  "           if (input.value.trim() !== "") {\n"                                                                                                                                                       \
  "               web_send_usb_data();\n"                                                                                                                                                                 \
  "           } else {\n"                                                                                                                                                                                 \
  "               alert('输入框不能为空!');\n"                                                                                                                                                           \
  "           }\n"                                                                                                                                                                                        \
  "       }\n"                                                                                                                                                                                            \
  "       function page_load() {\n"                                                                                                                                                                       \
  "           get_netinfo();\n"                                                                                                                                                                           \
  "			      update_page();\n"                                                                                                                                                                             \
  "           readContent();\n"                                                                                                                                                                           \
  "       }\n"                                                                                                                                                                                            \
  "    </script>\n"                                                                                                                                                                                       \
  "</body>\n"                                                                                                                                                                                                 \
  "</html>"

#endif

通过宏定义HTML_PAGE构建了一个完整的 W55MH32 设备用户配置网页,该网页集成了温湿度显示、LED / 蜂鸣器控制、EEPROM 测试、SD 卡读写、网络参数配置、USB 串口通信等功能,并通过 AJAX 与后端 CGI 接口交互实现数据的实时更新和指令下发。

步骤1:外设及网络配置初始化

先完成 MCU 各类底层外设(时钟、延时、中断、串口、USB、定时器、GPIO、I2C)的初始化,再初始化 WIZnet 芯片的 TCP/IP 协议栈;随后按需加载默认 MAC 地址,检查以太网物理链路状态,从 EEPROM 读取并配置网络参数到芯片,最后读取芯片当前生效的网络参数,以此完成网络通信前的全部初始化准备。

wiz_NetInfo net_info;

    /* hardware initialization */
    rcc_clk_config();
    delay_init();
	  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
	  console_usart_init(115200);
	  usb_init();
    
		delay_ms(200);
    printf("%s factory firmware\r\n", _WIZCHIP_ID_);
    tim3_init();
    user_gpio_init();
    i2c_CfgGpio();
    
    
    MYI2C_Init(&SENx, 1000, 0x38);
	//ee_Erase();
    /* wiztoe init */
    wiz_toe_init();
#if DEFAULT_MAC_EN == 1
    getSHAR(default_net_info.mac);
#endif

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

    wizchip_getnetinfo(&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;
}

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

reg_httpServer_webContent((uint8_t *)"index.html", (uint8_t *)HTML_PAGE);
httpServer_init(http_tx_ethernet_buf, http_rx_ethernet_buf, _WIZCHIP_SOCK_NUM_, socknumlist); // Initializing the HTTP server

步骤3:注册TIM3 中断驱动

void TIM3_IRQHandler(void)
{
    static uint32_t tim3_1ms_count   = 0;
    static uint8_t  tim3_100ms_count = 0;
    if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
    {
        tim3_1ms_count++;
        tim3_100ms_count++;
        btn_timer_cnt++;
        if (btn_timer_flag && btn_timer_cnt >= 20)
        {
            btn_timer_flag = 0;
            if ((GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_6) == RESET))
            {
                btn_cnt++;
            }
        }
        if (tim3_100ms_count >= 100)
        {
            tim3_100ms_count = 0;
            MYI2C_Handle(&SENx);
        }
        if (tim3_1ms_count >= 1000)
        {
            DHCP_time_handler();
            httpServer_time_handler();
            tim3_1ms_count = 0;
        }
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
    }
}

该函数作为 TIM3 定时器的中断处理函数,在 1ms 中断周期内累计计时,分别实现 20ms 按键状态检测、100ms 温湿度传感器 I2C 数据处理、1000ms DHCP 和 HTTP 服务器的定时任务处理,并在每次中断结束后清除中断标志位。

步骤4:运行HTTP和USB功能以及重启检测

    while (1)
    {
        httpServer_run(SOCKET_ID);
        if (reboot_flag)
        {
            NVIC_SystemReset();
        }
        usb_run();
    }

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; // Structure of HTTP Request
  parsed_http_request = (st_http_request *)pHTTP_TX;

  // Get the H/W socket number
  s = getHTTPSocketNum(seqnum);

  /* HTTP Service Start */
  switch (getSn_SR(s))
  {
  case SOCK_ESTABLISHED:
      // Interrupt clear
      if (getSn_IR(s) & Sn_IR_CON)
      {
          setSn_IR(s, Sn_IR_CON);
      }

      // HTTP Process states
      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);
#ifdef _HTTPSERVER_DEBUG_
              getSn_DIPR(s, destip);
              destport = getSn_DPORT(s);
              printf("\r\n");
              printf("> HTTPSocket[%d] : HTTP Request received ", s);
              printf("from %d.%d.%d.%d : %d\r\n", destip[0], destip[1], destip[2], destip[3], destport);
#endif
#ifdef _HTTPSERVER_DEBUG_
              printf("> HTTPSocket[%d] : [State] STATE_HTTP_REQ_DONE\r\n", s);
#endif
              // HTTP 'response' handler; includes send_http_response_header / body function
              http_process_handler(s, parsed_http_request);

              gettime = get_httpServer_timecount();
              // Check the TX socket buffer for End of HTTP response sends
              while (getSn_TX_FSR(s) != (getSn_TxMAX(s)))
              {
                  if ((get_httpServer_timecount() - gettime) > 3)
                  {
#ifdef _HTTPSERVER_DEBUG_
                      printf("> HTTPSocket[%d] : [State] STATE_HTTP_REQ_DONE: TX Buffer clear timeout\r\n", s);
#endif
                      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; // Send the 'HTTP response' end
          }
          break;

      case STATE_HTTP_RES_INPROC:
          /* Repeat: Send the remain parts of HTTP responses */
#ifdef _HTTPSERVER_DEBUG_
          printf("> HTTPSocket[%d] : [State] STATE_HTTP_RES_INPROC\r\n", s);
#endif
          // Repeatedly send remaining data to client
          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:
#ifdef _HTTPSERVER_DEBUG_
          printf("> HTTPSocket[%d] : [State] STATE_HTTP_RES_DONE\r\n", s);
#endif
          // Socket file info structure re-initialize
          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;

//#ifdef _USE_SDCARD_
//					f_close(&fs);
//#endif
#ifdef _USE_WATCHDOG_
          HTTPServer_WDT_Reset();
#endif
          http_disconnect(s);
          break;

      default:
          break;
      }
      break;

  case SOCK_CLOSE_WAIT:
#ifdef _HTTPSERVER_DEBUG_
      printf("> HTTPSocket[%d] : ClOSE_WAIT\r\n", s); // if a peer requests to close the current connection
#endif
      disconnect(s);
      break;

  case SOCK_CLOSED:
      if (reboot_flag)
      {
          NVIC_SystemReset();
      }
#ifdef _HTTPSERVER_DEBUG_
      printf("> HTTPSocket[%d] : CLOSED\r\n", s);
#endif
      if (socket(s, Sn_MR_TCP, HTTP_SERVER_PORT, 0x00) == s) /* Reinitialize the socket */
      {
#ifdef _HTTPSERVER_DEBUG_
          printf("> HTTPSocket[%d] : OPEN\r\n", s);
#endif
      }
      break;

  case SOCK_INIT:
      listen(s);
      break;

  case SOCK_LISTEN:
      break;

  default:
      break;

  } // end of switch

#ifdef _USE_WATCHDOG_
  HTTPServer_WDT_Reset();
#endif
}

usb_run()作为 USB 虚拟串口的核心处理函数,先检测 USB 设备连接状态是否变化,更新连接标志并打印连接 / 断开信息,再判断是否有新的 USB 串口数据接收完成,若有则获取数据长度、将数据拷贝至循环缓存数组、回显数据并清空接收标志,同时循环管理缓存索引避免越界。

void usb_run(void)
{
    uint16_t len;
    if (usbstatus != bDeviceState)
    {
        usbstatus = bDeviceState;
        if (usbstatus == CONFIGURED)
        {
            usb_conn_flag = 1;
            printf("USB connected\r\n");
        }
        else
        {
            usb_conn_flag = 0;
            printf("USB disconnected\r\n");
        }
    }
    if (USB_USART_RX_STA & 0x8000)
    {
        len = USB_USART_RX_STA & 0x3FFF;
        strncpy((char *)(usb_data[data_cnt]), (char *)USB_USART_RX_BUF, len);
        //sprintf((char*)(usb_data[data_cnt]),"%s",(char*)USB_USART_RX_BUF);
        usb_printf("Tx->:%s\r\n", usb_data[data_cnt]);
        USB_USART_RX_STA = 0;
        if (data_cnt < 18)
        {
            data_cnt++;
        }
        else
        {
            data_cnt = 0;
        }
    }
}

步骤5:请求内容处理

POST方式的CGI请求处理,在httpUtil.c文件的predefined_set_cgi_processor()函数中处理。

GET方式的CGI请求处理,在httpUtil.c文件的predefined_get_cgi_processor()函数中处理。

predefined_set_cgi_processor()函数作为 CGI 请求处理器,根据传入的 URI 名称匹配 todo.cgi、set_io_state.cgi 等不同 CGI 指令,执行 LED / 蜂鸣器控制、USB 数据发送、SD 卡文件写入等对应操作,并将执行结果以 JS 语句形式写入缓冲区、设置返回数据长度,最终返回 URI 名称的匹配状态。

uint8_t predefined_set_cgi_processor(uint8_t *uri_name, uint8_t *uri, uint8_t *buf, uint16_t *len)
{
    uint8_t ret = 1; // ret = '1' means 'uri_name' matched

    if (strcmp((const char *)uri_name, "todo.cgi") == 0)
    {
        // to do
        ;   // val = todo(uri);
            //*len = sprintf((char *)buf, "%d", val);
    }
    else if (strcmp((const char *)uri_name, "set_io_state.cgi") == 0)
    {
        uint8_t *param;
        uint8_t  name[10];
        uint8_t  val;
        param = get_http_param_value((char *)uri, "name");
        if (param) // GPIO;
        {
            strcpy((char *)name, (char *)param);
            param = get_http_param_value((char *)uri, "val");
            if (param) // State; high(on)/low(off)
            {
                val = (uint8_t)ATOI(param, 10);
            }
            if (strcmp((char *)name, (char *)"led") == 0)
            {
                if (val == 1)
                {
                    led_on();
                }
                else
                {
                    led_off();
                }
            }
            if (strcmp((char *)name, (char *)"beep") == 0)
            {
                if (val == 1)
                {
                    beep_on();
                }
                else
                {
                    beep_off();
                }
            }
        }
        *len = sprintf((char *)buf, "console.log('%s is %s');", name, val ? "on" : "off");
    }
    else if (strcmp((const char *)uri_name, "set_netinfo.cgi") == 0)
    {
        set_netinfo(uri, buf, len);
    }
    else if (strcmp((const char *)uri_name, "web_send_usb_data.cgi") == 0)
    {
        uint8_t *param;
        if (usb_conn_flag)
        {
            param = get_http_param_value((char *)uri, "data");
            if (param)
            {
                *len = sprintf((char *)buf, "$('usb-textbox').value='Tx->:'+$('usb-input').value+'\\n'+$('usb-textbox').value;");
                usb_printf("Rx->:%s\r\n", param);
            }
        }
        else
        {
            *len = sprintf((char *)buf, "alert('USB未连接');");
        }
    }
    else if (strcmp((const char *)uri_name, "put_sd.cgi") == 0)
    {
        uint8_t  filename[255];
        uint16_t filelen;
        uint8_t *param;
        param = get_http_param_value((char *)uri, "filename");
        if (param) // GPIO;
        {
            strcpy((char *)filename, (char *)param);
        }
        param = get_http_param_value((char *)uri, "filelen");
        if (param) // GPIO;
        {
            filelen = ATOI(param, 10);
        }
        param = get_http_param_value((char *)uri, "filedata");
        if (put_sd(filename, param, filelen))
        {
            *len = sprintf((char *)buf, "alert('存储成功');readContent();");
        }
        else
        {
            *len = sprintf((char *)buf, "alert('存储文件失败!请检查SD卡是否正确插入!')");
        }
    }
    else
    {
        ret = 0;
    }

    return ret;
}

predefined_get_cgi_processor()函数作为 CGI 读请求处理器,依据传入的 URI 名称匹配 todo.cgi、check_eeprom.cgi 等不同 CGI 指令,执行 eeprom 测试、获取网络信息、生成更新页面、读取 SD 卡文件名列表等操作,将结果以 JS 语句或 JSON 形式写入缓冲区并设置返回数据长度,最终返回 URI 名称的匹配状态。

uint8_t predefined_get_cgi_processor(uint8_t *uri_name, uint8_t *buf, uint16_t *len)
{
    uint8_t ret = 1; // ret = 1 means 'uri_name' matched

    if (strcmp((const char *)uri_name, "todo.cgi") == 0)
    {
        // to do
        ; // make_json_todo(buf, len);
    }
    else if (strcmp((const char *)uri_name, "check_eeprom.cgi") == 0)
    {
        if(ee_Test())
        {
            *len = sprintf((char *)buf, "alert('eeprom测试通过!');");
        }
        else
        {
            *len = sprintf((char *)buf, "alert('eeprom测试失败!');");
        }
    }
    else if (strcmp((const char *)uri_name, "get_netinfo.cgi") == 0)
    {
        make_json_netinfo(buf, len);
    }
    else if (strcmp((const char *)uri_name, "get_update_page.cgi") == 0)
    {
        make_json_update_page(buf, len);
    }
    else if (strcmp((const char *)uri_name, "get_sd.cgi") == 0)
    {
        uint8_t temp[255] = {0};
        uint8_t i;
        if (get_sd_filename() == 0)
        {
            *len = sprintf((char *)buf, "alert('SD卡未插入或识别异常!');");
        }
        else
        {
            memset(send_data, 0, sizeof(send_data));
            // printf("file_cnt:%d\r\n", file_cnt);
            for (i = 0; i < file_cnt; i++)
            {
                sprintf((char *)temp, "%s\\n", file_name[i]);
                strcat((char *)send_data, (char *)temp);
            }
            // printf("send_data:%s\r\n", send_data);
            *len = sprintf((char *)buf, "$('sd-textbox').value=\"%s\";", send_data);
            memset(send_data, 0, sizeof(send_data));
            memset(file_name, 0, sizeof(file_name));
            file_cnt = 0;
        }
    }
    else
    {
        ret = 0;
    }
    return ret;
}

步骤6:重启设备

当网络配置被修改后再进行复位操作, 避免出现客户端请求后,W55MH32未响应就重启导致客户端请求超时的情况。

if (reboot_flag)
{
    NVIC_SystemReset();
}

运行结果

烧录例程运行后,首先进行了PHY链路检测,然后是通过DHCP获取网络地址并打印网络地址信息, 最后HTTP Server程序开始监听客户端的请求并处理响应,如下图所示:

W55MH32 用户配置界面设置如下

接下来,我们会分别对 SD 卡读写、USB 串口功能以及网络配置参数修改这几个功能点进行测试。

我们先测试SD卡的读写, HTTP 服务器接收到get_sd.cgi请求后,成功识别 SD 卡并读取到 4 个文件的文件名列表返回给客户端。

在W55MH32 用户配置界面操作如下:

接下来,我们再对 USB 串口的发送功能进行测试。

最后,我们在用户配置界面完成W55MH32网络参数的修改测试。

总结

本文介绍了 W55MH32 芯片网页用户配置界面的实现方案,其实现流程涵盖外设及网络配置初始化、网页内容与 HTTP Server 注册、中断驱动配置、功能运行及请求处理等关键步骤,成功在网页端实现温湿度显示、LED / 蜂鸣器控制、SD 卡读写、USB 串口通信、网络参数配置等核心功能,实测验证该网页配置界面操作便捷、稳定可靠,为嵌入式设备的网络化管控提供了简洁高效的实现思路。

下载本章例程

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

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