STM32 W5500 HTTP Server 微型web服务实现

嵌入式Web服务很常见,比如电脑通过WIFI接入网络,在浏览器地址栏输入 "192.168.1.1",或者其他地址,跟自己电脑的IP在同一个网段内,一般IP最后一段是1即可,可以打开路由器的管理页面。就像这样:

STM32 W5500 HTTP Server 微型web服务实现_第1张图片

这个页面就是有嵌入式小型web服务提供的网页。

STM32 W5500几乎也可以实现上述的功能,但是由于STM32的RAM和FLASH储存大小是有限的,实现一个简单的web服务是没有问题的。

STM32 W5500实现一个简单的web服务需要具备的几个条件:

1、STM32 W5500的基础入网配置,可以PING通,可以参考《STM32F103RC驱动W5500入网,并可ping通》

2、STM32 W5500的TCP Server回环测试没有问题,可以参考 《STM32 W5500 TCP Server 回环测试》

3、对HTTP协议有一定的认识。

确定一下要实现的web服务的功能,STM32 W5500配置入网后,通过DHCP动态获取IP地址,在电脑浏览器地址栏输入这个IP地址,可以获取到一个简单form表单的页面,在表单中输入数据,提交到W5500web服务,返回一个结果。如图:

STM32 W5500 HTTP Server 微型web服务实现_第2张图片

功能比较简单,比较费事儿的是字符串的处理接收到的字符串的解析,以及返回信息的组装。

直接贴出测试的代码:

#ifndef __STM32F10X_H
#define __STM32F10X_H
#include "stm32f10x.h"
#endif

#ifndef __Z_UTIL_TIME_H
#define __Z_UTIL_TIME_H
#include "z_util_time.h"
#endif

#ifndef __Z_HARDWARE_LED_H
#define __Z_HARDWARE_LED_H
#include "z_hardware_led.h"
#endif

#ifndef __Z_HARDWARE_SPI_H
#define __Z_HARDWARE_SPI_H
#include "z_hardware_spi.h"
#endif

#ifndef __W5500_H
#define __W5500_H
#include "w5500.h"
#endif

#ifndef __SOCKET_H
#define __SOCKET_H
#include "socket.h"
#endif

#ifndef __W5500_CONF_H
#define __W5500_CONF_H
#include "w5500_conf.h"
#endif

#ifndef __DHCP_H
#define __DHCP_H
#include "dhcp.h"
#endif

#ifndef __Z_HARDWARE_USART2_H
#define __Z_HARDWARE_USART2_H
#include "z_hardware_usart2.h"
#endif

#include "MQTTPacket.h"

#ifndef __IMPL_MQTT_H
#define __IMPL_MQTT_H
#include "impl_mqtt.h"
#endif

#define SOCK_TCPS 0
#define BUFFER_SIZE 1536
#define TEXT_TEMPLATE_OK "HTTP/1.1 200 OK\r\n"\
"Content-Type: text/html\r\n"\
"Content-Length: %d\r\n"\
"Connection: keep_alive\r\n\r\n%s"

#define TEXT_TEMPLATE_ERR "HTTP/1.1 404 Not Found\r\n"\
"Content-Length: 0\r\n\r\n"\
"Connection: keep_alive\r\n\r\n"

#define HTML_CONTENT ""\
""\
""\
""\
"SN Config"\
""\
""\
""\
"
"\ "
"\ "SN:"\ ""\ "
"\ "
"\ "
"\ "

System SN Config

"\ "
"\ ""\ "\r\n" #define HTML_RESULT_OK ""\ ""\ ""\ ""\ "SN Config"\ ""\ ""\ ""\ "
"\ "

System SN Config OK

"\ "
"\ ""\ "\r\n" #define HTML_RESULT_ERR ""\ ""\ ""\ ""\ "SN Config"\ ""\ ""\ ""\ "
"\ "

System SN Config FAIL

"\ "
"\ ""\ "\r\n" u8 func_analysis_http_request(u8* buffer, u16 len_recv, char* method, char* uri, char* data_body); u8 func_package_http_response(u8* buffer, u16 *len_ret, u16 len_buf, char* cont, u16 len_cont); int main(void) { u32 dhcp_timestamp; u8 mac[6]={0, }; DHCP_Get dhcp_get; u16 len; u8 buffer[BUFFER_SIZE]; char http_method[16]; char http_uri[64]; char http_body[256]; u8 res_code; systick_configuration(); init_led(); init_system_spi(); func_w5500_reset(); init_hardware_usart2_dma(9600); getMacByLockCode(mac); setSHAR(mac); sysinit(txsize, rxsize); setRTR(2000); setRCR(3); //DHCP for(;func_dhcp_get_ip_sub_gw(1, mac, &dhcp_get, 500) != 0;); if(func_dhcp_get_ip_sub_gw(1, mac, &dhcp_get, 500) == 0) { setSUBR(dhcp_get.sub); setGAR(dhcp_get.gw); setSIPR(dhcp_get.lip); close(1); } dhcp_timestamp = get_systick_timestamp(); for(;;) { if(get_systick_timestamp() - dhcp_timestamp > 59*1000)// 1 min dhcp { dhcp_timestamp = get_systick_timestamp(); if(func_dhcp_get_ip_sub_gw(1, mac, &dhcp_get, 500) == 0) { setSUBR(dhcp_get.sub); setGAR(dhcp_get.gw); setSIPR(dhcp_get.lip); close(1); } } switch(getSn_SR(SOCK_TCPS)) { case SOCK_CLOSED: socket(SOCK_TCPS, Sn_MR_TCP, 80, Sn_MR_ND); break; case SOCK_INIT: listen(SOCK_TCPS); break; case SOCK_ESTABLISHED: if(getSn_IR(SOCK_TCPS) & Sn_IR_CON) { setSn_IR(SOCK_TCPS, Sn_IR_CON); } len = getSn_RX_RSR(SOCK_TCPS); if(len>0) { memset(buffer, 0, BUFFER_SIZE); len = recv(SOCK_TCPS, buffer, len); //analysis tcp msg, and package the feedback msg if(len > 0) { res_code = func_analysis_http_request(buffer, len, http_method, http_uri, http_body); memset(buffer, 0, sizeof(buffer)); if(res_code == 0) { if(strcmp("GET", http_method) == 0 && strcmp("/", http_uri) == 0) { func_package_http_response(buffer, &len, sizeof(buffer), HTML_CONTENT, strlen(HTML_CONTENT)); send(SOCK_TCPS, buffer, len); } else if(strcmp("POST", http_method) == 0 && strcmp("/sn_config.action", http_uri) == 0) { func_package_http_response(buffer, &len, BUFFER_SIZE, HTML_RESULT_OK, strlen(HTML_RESULT_OK)); send(SOCK_TCPS, buffer, len); } else { memcpy(buffer, TEXT_TEMPLATE_ERR, strlen(TEXT_TEMPLATE_ERR)); send(SOCK_TCPS, buffer, strlen(TEXT_TEMPLATE_ERR)); } disconnect(SOCK_TCPS); } else { memcpy(buffer, TEXT_TEMPLATE_ERR, strlen(TEXT_TEMPLATE_ERR)); send(SOCK_TCPS, buffer, strlen(TEXT_TEMPLATE_ERR)); disconnect(SOCK_TCPS); } } } break; case SOCK_CLOSE_WAIT: close(SOCK_TCPS); break; } func_led1_on(); delay_ms(500); func_led1_off(); delay_ms(500); } } u8 func_analysis_http_request(u8* buffer, u16 len_recv, char* method, char* uri, char* data_body) { char chs[BUFFER_SIZE] = {0, }; char *res, *end; if(len_recv > 0) { memcpy(chs, buffer, 3); res = strstr(chs, "GET"); if(strcmp("GET", res) == 0) { memcpy(method, "GET", strlen("GET")); } else { memset(chs, 0, BUFFER_SIZE); memcpy(chs, buffer, 4); res = strstr(chs, "POST"); if(strcmp("POST", res) == 0) { memcpy(method, "POST", strlen("POST")); } else { return 1; } } memset(chs, 0, BUFFER_SIZE); memcpy(chs, buffer, len_recv + 1); res = strchr(chs, '/'); if(res != NULL) { end = strchr(res, ' '); if(end != NULL) { memcpy(uri, res, end - res); } } memset(chs, 0, BUFFER_SIZE); memcpy(chs, buffer, len_recv + 1); res = strstr(chs, "\r\n\r\n"); if(res != NULL) { if(strlen(res) > 4) { memcpy(data_body, res + 4, strlen(res) - 4); } } } return 0; } u8 func_package_http_response(u8* buffer, u16 *len_ret, u16 len_buf, char* cont, u16 len_cont) { memset(buffer, 0, BUFFER_SIZE); *len_ret = sprintf((char*)buffer, TEXT_TEMPLATE_OK, len_cont, cont); return 0; }

相关的基础函数库可以参考我的其他文章。

测试步骤,我的W5500的IP是动态获取到的,所以先登录到路由器管理页面查看他的IP地址。

STM32 W5500 HTTP Server 微型web服务实现_第3张图片

我的 STM32 W5500 IP地址是"192.168.1.100"。在浏览器地址栏输入"192.168.1.100",可以看到页面

STM32 W5500 HTTP Server 微型web服务实现_第4张图片

在SN后的input标签内输入任意内容,点击submit后,可以看到

STM32 W5500 HTTP Server 微型web服务实现_第5张图片

数据已提交到服务。

通过Debug单步调试可以看到浏览器提交到的数据内容,或者通过串口打印出来。一般的操作都是收到这个数据后存储到EEPROM中。

你可能感兴趣的:(STM32,W5500,HTTP)