STM32
直播中

李微波

7年用户 926经验值
私信 关注
[问答]

怎么实现STM32 W5500 HTTP Server微型web服务?

怎么实现STM32 W5500 HTTP Server微型web服务?

回帖(1)

李丽

2021-11-26 11:26:16
嵌入式Web服务很常见,比如电脑通过WIFI接入网络,在浏览器地址栏输入 "192.168.1.1",或者其他地址,跟自己电脑的IP在同一个网段内,一般IP最后一段是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服务,返回一个结果。如图:





功能比较简单,比较费事儿的是字符串的处理接收到的字符串的解析,以及返回信息的组装。
直接贴出测试的代码:

#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 OKrn"
"Content-Type: text/htmlrn"
"Content-Length: %drn"
"Connection: keep_alivernrn%s"

#define TEXT_TEMPLATE_ERR "HTTP/1.1 404 Not Foundrn"
"Content-Length: 0rnrn"
"Connection: keep_alivernrn"

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

System SN Config

"
"
"
""
"rn"

#define HTML_RESULT_OK ""
""
""
""
"SN Config"
""
""
""
"
"
"

System SN Config OK

"
"
"
""
"rn"

#define HTML_RESULT_ERR ""
""
""
""
"SN Config"
""
""
""
"
"
"

System SN Config FAIL

"
"
"
""
"rn"

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, "rnrn");
                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 IP地址是"192.168.1.100"。在浏览器地址栏输入"192.168.1.100",可以看到页面





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





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

更多回帖

发帖
×
20
完善资料,
赚取积分