STM32F1网络编程-HTTP服务器(基于W5500网卡)

HTTP服务器(基于W5500网卡)

HTTP是超文本传输协议(Hyper Text Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常运行在TCP之上。HTTP服务器本质是TCP服务器。W5500驱动实现HTTP服务器的简单封装,并提供简单灵活的调用接口。本次实例将演示如何使用W5500的HTTP服务器接口。

W5500驱动的HTTP服务器接口主要调用步骤如下:

  • 1)初始化HTTP服务器
  • 2)注册HTTP服务硬件重置函数
  • 3)注册HTTP服务器页面
  • 4)实现HTTP服务请求响应
  • 5)监听HTTP请求

关于W5500的驱动移植及IP设置、获取,请参考:

关于TCP通信过程,请参考:

关于远程主机IP查询,请参考:

本次实现的HTTP功能如下:

  • 1)查询网卡信息
  • 2)控制3个LED灯的点亮与熄灭

1、HTTP服务器配置

关于STM32CubeIDE工程创建、配置请参考前面文章:

本次HTTP服务器的配置如下:

在这里插入图片描述

2、HTTP服务器请求响应实现

在W5500驱动中,HTTP服务器请求响应的实现的定义如下:

在这里插入图片描述

为了方便,本次实例将这两个函数注释掉,然后在工程的Application目录中分别创建http_user_handler.hhttp_user_handler.c文件,并在这两个文件中实现。其内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/\*
\* http\_user\_handler.h
\*
\* Created on: 2022年7月15日
\* Author: jenson
\*/

#ifndef HTTP\_USER\_HANDLER\_H\_
#define HTTP\_USER\_HANDLER\_H\_

#include <stdint.h>
//#define \_WEB\_DEBUG\_

uint8\_t predefined\_get\_cgi\_processor(uint8\_t \* uri_name, uint8\_t \* buf, uint16\_t \* len);
uint8\_t predefined\_set\_cgi\_processor(uint8\_t \* uri_name, uint8\_t \* uri, uint8\_t \* buf, uint16\_t \* len);

#endif /\* HTTP\_USER\_HANDLER\_H\_ \*/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/\*
\* http\_user\_hander.c
\*
\* Created on: 2022年7月15日
\* Author: jenson
\*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "httpserver/httpUtil.h"
#include "http\_user\_handler.h"
#include "wizchip\_conf.h"
#include "main.h"

void make\_json\_netinfo(uint8\_t \*buf, uint16\_t \*len);

int8\_t set\_diostate(uint8\_t \*uri);

// GET请求
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
uint8\_t cgibuf[14] = { 0, };
int8\_t cgi_dio = -1;
int8\_t cgi_ain = -1;

uint8\_t i;

if (strcmp((const char\*) uri_name, "get\_netinfo.cgi") == 0) {
make\_json\_netinfo(buf, len);
}

return ret;
}

// POST请求
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
uint8\_t val = 0;

if (strcmp((const char\*) uri_name, "set\_diostate.cgi") == 0) {
val = set\_diostate(uri);
\*len = sprintf((char\*) buf, "%d", val);
} else {
ret = 0;
}

return ret;
}


void make\_json\_netinfo(uint8\_t \*buf, uint16\_t \*len) {
wiz_NetInfo netinfo;
ctlnetwork(CN_GET_NETINFO, (void\*) &netinfo);

// DHCP: 1 - Static, 2 - DHCP
\*len =
sprintf((char\*) buf,
"NetinfoCallback({\"mac\":\"%.2X:%.2X:%.2X:%.2X:%.2X:%.2X\",\
\"ip\":\"%d.%d.%d.%d\",\
\"gw\":\"%d.%d.%d.%d\",\
\"sn\":\"%d.%d.%d.%d\",\
\"dns\":\"%d.%d.%d.%d\",\
\"dhcp\":\"%d\"\
});",
netinfo.mac[0], netinfo.mac[1], netinfo.mac[2],
netinfo.mac[3], netinfo.mac[4], netinfo.mac[5],
netinfo.ip[0], netinfo.ip[1], netinfo.ip[2], netinfo.ip[3],
netinfo.gw[0], netinfo.gw[1], netinfo.gw[2], netinfo.gw[3],
netinfo.sn[0], netinfo.sn[1], netinfo.sn[2], netinfo.sn[3],
netinfo.dns[0], netinfo.dns[1], netinfo.dns[2],
netinfo.dns[3], netinfo.dhcp);
}

#define LED1 0x01
#define LED2 0x02
#define LED3 0x03
#define LED4 0x04
int8\_t set\_diostate(uint8\_t \*uri) {
uint8\_t \*param;
uint8\_t pin = 0, val = 0;

if ((param = get\_http\_param\_value((char\*) uri, "pin")))
{
pin = (uint8\_t) ATOI(param, 10);
if (pin > 15)
return -1;

if ((param = get\_http\_param\_value((char\*) uri, "val")))
{
val = (uint8\_t) ATOI(param, 10);
if (val > On)
val = On;
}
printf("led %d,state = %d\r\n", pin, val);
switch (pin) {
case LED1:
HAL\_GPIO\_WritePin(LED1_GPIO_Port, LED1_Pin, val);
break;
case LED2:
HAL\_GPIO\_WritePin(LED2_GPIO_Port, LED2_Pin, val);
break;
case LED3:
HAL\_GPIO\_WritePin(LED3_GPIO_Port, LED3_Pin, val);
break;
case LED4:
HAL\_GPIO\_WritePin(LED4_GPIO_Port, LED4_Pin, val);
break;
}
}

return pin;
}


3、HTTP服务器页面定义

在工程的Application目录中添加webpage.h文件,并添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#ifndef \_WEBPAGE\_H\_
#define \_WEBPAGE\_H\_

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\* JavaScript Functions
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/

#define wiz550web\_ajax\_js "function AJAX(a,e){var c=d();c.onreadystatechange=b;function d(){if(window.XMLHttpRequest){return new XMLHttpRequest()}else{if(window.ActiveXObject){return new ActiveXObject(\"Microsoft.XMLHTTP\")}}}function b(){if(c.readyState==4){if(c.status==200){if(e){e(c.responseText)}}}}this.doGet=function(){c.open(\"GET\",a,true);c.send(null)};this.doPost=function(f){c.open(\"POST\",a,true);c.setRequestHeader(\"Content-Type\",\"application/x-www-form-urlencoded\");c.setRequestHeader(\"ISAJAX\",\"yes\");c.send(f)}}function $(a){return document.getElementById(a)}function $$(a){return document.getElementsByName(a)}function $$\_ie(a,c){if(!a){a=\"\*\"}var b=document.getElementsByTagName(a);var e=[];for(var d=0;d<b.length;d++){att=b[d].getAttribute(\"name\");if(att==c){e.push(b[d])}}return e}"

/\* Get: Network Information: function NetinfoCallback(o), getNetinfo() \*/
#define wiz550web\_netinfo\_js "function NetinfoCallback(o){"\
"$('txtmac').value=o.mac;"\
"$('txtip').value=o.ip;"\
"$('txtgw').value=o.gw;"\
"$('txtsn').value=o.sn;"\
"$('txtdns').value=o.dns;"\
"if(typeof(window.external)!='undefined'){"\
"obj=$$\_ie('input','dhcp');"\
"}else{"\
"obj=$$('dhcp');"\
"}"\
"}"\
" "\
"function getNetinfo(){"\
"var oUpdate;"\
"setTimeout(function(){"\
"oUpdate=new AJAX('get\_netinfo.cgi',function(t){"\
"try{eval(t);}catch(e){alert(e);}"\
"});"\
"oUpdate.doGet();},300);"\
"}"

#define wiz550web\_dio\_js "function DioCallback(o){"\
"var pin = o.dio\_p;"\
"$('txtdio\_s'+pin).value=o.dio\_s;"\
"$('txtdio\_d'+pin).value=o.dio\_d;"\
"}"\
"function getDio(o) {"\
"var p=o.attributes['pin'].value;"\
"var oUpdate;"\
"oUpdate=new AJAX('get\_dio'+p+'.cgi',function(t){try{eval(t);}catch(e){alert(e);}});"\
"oUpdate.doGet();"\
"}"\
" "\
"function setDiostate(o){"\
"var p=o.attributes['pin'].value;"\
"/\*var v=$('txtdio\_s'+p).value;\*/"\
"var v=o.attributes['s'].value;"\
"dout=new AJAX('set\_diostate.cgi', function(t){try{eval(t);}catch(e){alert(e);}});"\
"dout.doPost('pin='+p+'&val='+v);"\
"}"\
" "\
"function setDiodir(o){"\
"var p=o.attributes['pin'].value;"\
"/\*var v=$('txtdio\_d'+p).value;\*/"\
"var v=o.attributes['d'].value;"\
"dout=new AJAX('set\_diodir.cgi', function(t){try{eval(t);}catch(e){alert(e);}});"\
"dout.doPost('pin='+p+'&val='+v);"\
"}"

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\* HTML Pages (web pages)
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
// 主页
#define index\_page "<html>"\
"<head>"\
"<title>W5500-EVB Web Server</title>"\
"<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>"\
"</head>"\
"<body>"\
"<div>"\
"W5500-EVB Web Server Demopage"\
"</div>"\
"<br>"\
"<a href='netinfo.html'>Network Information</a>"\
"<br>"\
"<a href='dio.html'>Ex1> Digital I/O</a>"\
"<br>"\
"</html>"


#define netinfo\_page "<!DOCTYPE html>"\
"<html>"\
"<head>"\
"<title>W5500-EVB Web Server Network Info</title>"\
"<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>"\
"<style>"\
"label{float:left;text-align:left;width:50px;}"\
"li {list-style:none;}"\
"</style>"\
"<script type='text/javascript' src='ajax.js'></script>"\
"<script type='text/javascript' src='netinfo.js'></script>"\
"</head>"\
"<body οnlοad='getNetinfo();'>"\
"<div>"\
"W5500-EVB Web Server Network Information"\
"</div>"\
"<br>"\
"<ul>"\
"<li><label for='txtmac'>MAC:</label><input id='txtmac' name='mac' type='text' size='20' disabled='disabled'/></li> "\
"<li><label for='txtip'>IP:</label><input id='txtip' name='ip' type='text' size='20' disabled='disabled'/></li> "\
"<li><label for='txtgw'>GW:</label><input id='txtgw' name='gw' type='text' size='20' disabled='disabled'/></li> "\
"<li><label for='txtsn'>SN:</label><input id='txtsn' name='sn' type='text' size='20' disabled='disabled'/></li> "\
"<li><label for='txtdns'>DNS:</label><input id='txtdns' name='dns' type='text' size='20' disabled='disabled'/></li> "\
"</ul>"\
"</body>"\
"</html>"

// LED控制页面
#define dio\_page "<!DOCTYPE html>"\
"<html>"\
"<head>"\
"<title>W5500-EVB Web Server Digital I/O</title>"\
"<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>"\
"<script type='text/javascript' src='ajax.js'></script>"\
"<script type='text/javascript' src='dio.js'></script>"\
"</head>"\
"<body>"\
"<!-- to do -->"\
"<div>"\
"<input type='button' value='LED 1 On' pin='1' s='1' οnclick='setDiostate(this);'> "\
"<input type='button' value='LED 1 Off' pin='1' s= '0' οnclick='setDiostate(this);'>"\
"<br>"\
"<input type='button' value='LED 2 On' pin='2' s='1' οnclick='setDiostate(this);'> "\
"<input type='button' value='LED 2 Off' pin='2' s= '0' οnclick='setDiostate(this);'>"\
"<br>"\
"<input type='button' value='LED 3 On' pin='3' s='1' οnclick='setDiostate(this);'> "\
"<input type='button' value='LED 3 Off' pin='3' s= '0' οnclick='setDiostate(this);'>"\
"<br>"\
"<input type='button' value='LED 4 On' pin='4' s='1' οnclick='setDiostate(this);'> "\
"<input type='button' value='LED 4 Off' pin='4' s= '0' οnclick='setDiostate(this);'>"\
"</div>"\
"<!-- to do -->"\
"</body>"\
"</html>"


4、HTTP服务器调用实现

main.c文件中添加如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/\* Private includes ----------------------------------------------------------\*/
/\* USER CODE BEGIN Includes \*/
#include <stdio.h>
#include "w5500\_port.h"
#include <string.h> // memcmp
#include "httpServer/httpServer.h"
#include "webpage.h"

/\* USER CODE END Includes \*/


/\* Private macro -------------------------------------------------------------\*/
/\* USER CODE BEGIN PM \*/
#define \_MAIN\_DEBUG\_
#define MAX\_HTTPSOCK 6
#define SOCK\_TCPS 0
#define SOCK\_UDPS 1
#define PORT\_TCPS 5000
#define PORT\_UDPS 3000
#define DATA\_BUF\_SIZE 2048
uint8\_t socknumlist[] = { 2, 3, 4, 5, 6, 7 };
uint8\_t RX_BUF[DATA_BUF_SIZE];
uint8\_t TX_BUF[DATA_BUF_SIZE];
/\* USER CODE END PM \*/

int main(void) {
/\* USER CODE BEGIN 1 \*/

/\* USER CODE END 1 \*/

/\* MCU Configuration--------------------------------------------------------\*/

/\* Reset of all peripherals, Initializes the Flash interface and the Systick. \*/
HAL\_Init();

/\* USER CODE BEGIN Init \*/

/\* USER CODE END Init \*/

/\* Configure the system clock \*/
SystemClock\_Config();

/\* USER CODE BEGIN SysInit \*/

/\* USER CODE END SysInit \*/

/\* Initialize all configured peripherals \*/
MX\_GPIO\_Init();
MX\_USART1\_UART\_Init();
MX\_SPI1\_Init();
/\* USER CODE BEGIN 2 \*/
printf("-----STM32 W5500 Ethernet Demo-----\r\n");
w5500\_restart(); // hardware restart through RESET pin
wiznet\_register();
w5500\_network\_init();
wiznet\_chip\_config();

// HTTP Server 初始化
httpServer\_init(TX_BUF, RX_BUF, MAX_HTTPSOCK, socknumlist);
// 设置硬件重置回调
reg\_httpServer\_cbfunc(NVIC_SystemReset, NULL); // Callback: NXP MCU Reset

{
// 主页
reg\_httpServer\_webContent((uint8\_t\*) "index.html",
(uint8\_t\*) index_page);

// 网卡信息页面
reg\_httpServer\_webContent((uint8\_t\*) "netinfo.html",
(uint8\_t\*) netinfo_page);
reg\_httpServer\_webContent((uint8\_t\*) "netinfo.js",
(uint8\_t\*) wiz550web_netinfo_js)


// LED控制页面
reg\_httpServer\_webContent((uint8\_t\*) "dio.html", (uint8\_t\*) dio_page);
reg\_httpServer\_webContent((uint8\_t\*) "dio.js",
(uint8\_t\*) wiz550web_dio_js);


// AJAX JavaScript 函数
reg\_httpServer\_webContent((uint8\_t\*) "ajax.js",
(uint8\_t\*) wiz550web_ajax_js);

#ifdef \_MAIN\_DEBUG\_
display\_reg\_webContent\_list();
#endif
}
uint8\_t run_user_applications = 1;
/\* USER CODE END 2 \*/

/\* Infinite loop \*/
/\* USER CODE BEGIN WHILE \*/
while (1) {
/\* USER CODE END WHILE \*/

/\* USER CODE BEGIN 3 \*/
if (run_user_applications) {
for (uint8\_t i = 0; i < MAX_HTTPSOCK; i++)
httpServer\_run(i); // HTTP Server handler

loopback\_tcps(SOCK_TCPS, RX_BUF, 5000);

} // End of user's codeF
}
/\* USER CODE END 3 \*/
}

运行结果如下:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

文章来源: https://iotsmart.blog.csdn.net/article/details/125943352