快速上手!STM32实战教程之Web服务器实现 (stm32 web服务器教程)
随着物联网的普及,越来越多的设备需要通过Web访问来控制和监控。如何在嵌入式系统上实现一个高效稳定的Web服务器,成为了一个不可避免的问题。本文将介绍如何使用STM32系列微控制器实现一个简单的Web服务器,并通过实例演示如何实现一个具有实际应用价值的远程控制系统。
一、STM32开发环境搭建
为了使用STM32开发板实现Web服务器,我们需要先准备好必要的开发环境。此处以Windows平台为例,其他操作系统类似。
1. 软件准备
a) Keil MDK-ARM
Keil MDK-ARM是一款由英国Keil公司开发的 Cortex-M 系列微控制器开发环境,通过其专业的C语言编译器和强大的单片机仿真调试功能,可以轻松实现STM32的开发。
b) ST-LINK驱动程序
ST-LINK是ST公司推出的一款仿真调试接口,可与Keil等开发软件相连,用于下载程序和调试。在Windows下,需要安装相应的驱动程序。
c) sCons
sCons是一款功能强大的构建工具,可以自动化构建和管理工程,能够有效提高开发效率。
2. 硬件准备
a) STM32开发板
根据实际需求选择相应的STM32开发板,例如STM32F103ZET6开发板等。
b) 网络模块
为了实现Web服务器功能,我们需要一个支持TCP/IP协议栈的网络模块。
二、Web服务器实现
1. 基础功能实现
为了实现Web服务器功能,我们需要先实现网络通信的基础功能。这里使用W5500网络模块,具体实现过程如下。
a) 硬件连接
将W5500模块与STM32开发板相连接,具体连接方式如下。
W5500模块 | STM32开发板
———-|————-
MISO | PA6
MOSI | PA7
SCK | PA5
SS | PA4
RST | PA3
INT | PA2
VCC | VCC
GND | GND
b) 网络初始化
在mn函数中添加以下代码,用于初始化网络模块。
int mn(void)
{
NVIC_SetPriorityGrouping(NVIC_PriorityGroup_4);
W5500_Init();
//….
}
其中W5500_Init()函数用于初始化网络模块。
c) 建立TCP连接
在socket模块中添加以下代码,用于建立TCP连接。
if(sockstat == SOCK_UCAST_CLOSE_WT)
{
if((ret = connect(sn, destip, destport)) == SOCK_OK)
{
sockstat = SOCK_UCAST_ESTABLISHED;
}
}
其中,sn是SOCKET号,destip和destport是服务器的IP地址和端口号。
2. 远程控制系统实现
了解了Web服务器的基础功能,我们换一个角度思考,如何在嵌入式系统上实现一个具有实际价值的远程控制系统。下面是基于Web服务器的智能家居控制系统实现过程。
a) 硬件连接
在STM32开发板上加入控制模块(例如LED灯),并将模块与W5500模块相连接。具体连接方式如下。
W5500模块 | LED模块
———-|————-
INT | –
RST | –
SCK | SCK
MISO | MISO
MOSI | MOSI
SS | CS
VCC | VCC
GND | GND
b) 系统设计
通过Web浏览器访问服务器,将显示一个包含控制按钮的页面。用户单击按钮可以控制对应的LED灯亮灭。具体实现过程如下。
c) 网页设计
在Web服务器上建立一个名为“control.html”的页面,页面上添加两个按钮和一个文本框,用于提示控制状态。
控制按钮的代码如下。
其中,id属性用于给按钮一个唯一的标识,onclick属性用于定义按钮单击时的操作,sendCmd()函数将发送一个控制命令给服务器。
文本框代码如下。
其中,id属性用于给文本框一个唯一的标识,rows和cols属性用于设置文本框的大小,readonly属性用于设置文本框为只读模式。
d) 发送命令
在Web浏览器中单击按钮时,将调用sendCmd()函数,该函数将发送一个HTTP GET请求给Web服务器,请求的路径为“/control.cgi?cmd=[on|off]”,其中cmd参数表示控制命令(on表示打开LED灯,off表示关闭LED灯)。
void sendCmd(char *cmd)
{
char path[32];
sprintf(path, “/control.cgi?cmd=%s”, cmd);
uint8_t txbuf[1400];
memset(txbuf, 0, sizeof(txbuf));
//…
sprintf((char*)txbuf, GET_TEMPLATE, path, ip2str(ipaddr), port);
if((len = send(ch, txbuf, strlen((char*)txbuf), 0)) == SOCKET_ERROR)
{
return;
}
}
其中,GET_TEMPLATE为一个字符串常量,定义如下。
#define GET_TEMPLATE “GET %s HTTP/1.1\r\nHost: %s:%d\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:50.0) Gecko/20230101 Firefox/50.0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: en-US,en;q=0.5\r\nAccept-Encoding: gzip, deflate\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\n\r\n”
e) 处理命令
Web服务器收到来自Web浏览器的请求后,将调用相应的处理函数进行处理。在此处,我们先将请求的路径(即控制命令)解析出来,再调用相应的控制函数。
void handle_request(uint8_t ch, uint8_t *rxbuf, uint16_t len, uint8_t *ipaddr, uint16_t port)
{
//解析请求中的路径,获取控制命令
char *pcmd = strstr((char*)rxbuf, “cmd=”);
if(pcmd != NULL)
{
if(strncmp(pcmd + 4, “on”, 2) == 0)
{
led_on();
send_response(ch, “application/json”, “{\”status\”:\”ok\”,\”result\”:\”on\”}”);
}
else if(strncmp(pcmd + 4, “off”, 3) == 0)
{
led_off();
send_response(ch, “application/json”, “{\”status\”:\”ok\”,\”result\”:\”off\”}”);
}
else
{
send_response(ch, “application/json”, “{\”status\”:\”error\”,\”result\”:\”invalid command\”}”);
}
}
}
其中,led_on()和led_off()函数分别用于控制LED灯打开和关闭。
f) 响应命令
Web服务器处理完成命令后,需要将结果返回给Web浏览器。在此处,我们将使用ON格式返回响应信息。
void send_response(uint8_t ch, char *content_type, char *response)
{
uint8_t txbuf[1400];
memset(txbuf, 0, sizeof(txbuf));
char *header = “”
“HTTP/1.1 200 OK\r\n”
“Server: STM32 WebServer\r\n”
“Content-Type: %s\r\n”
“Cache-Control: no-cache\r\n”
“Content-Length: %d\r\n”
“Connection: keep-alive\r\n”
“\r\n”;
char *body = response;
int len = sprintf((char*)txbuf, header, content_type, strlen(body));
memcpy(txbuf + len, body, strlen(body));
if((send(ch, txbuf, len + strlen(body), 0)) == SOCKET_ERROR)
{
return;
}
}
三、
通过上述实例,我们了解了如何使用STM32系列微控制器实现一个简单的Web服务器,并通过演示如何实现一个具有实际应用价值的远程控制系统。为使该系统更加完善,我们还可以增加用户认证、消息推送等功能,以满足不同的应用场景。