STM32 W5500 HTTP Client POST 方式请求/提交网络数据

本文详细介绍了如何使用STM32W5500微控制器通过HTTPClient POST方式向远程服务器发送数据并接收JSON响应,涵盖了基础配置、代码实现及测试过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

现在想让STM32 W5500通过HTTP Client POST的方式提交数据到远程服务器,并接收服务返回的JSON格式数据,解析和处理。

实现以上功能,需要具备几个条件:

1、STM32 W5500的基础配置,使得PC和W5500在同一个局域网内,PC可以PING通W5500

2、STM32 W5500的TCP Client可以成功发数据,HTTP协议是基于TCP协议之上封装的协议。

3、远程服务器接口可以访问,可以通过POSTMAN工具先测试。

4、使用WireShark工具,追踪POSTMAN访问服务接口的报文数据,以及返回的报文数据。

STM32 W5500的基础配置和TCP Client我已具备条件,下面看下远程服务器接口是否可以访问:

Header部分:

Request Body和Response Body

接口返回了JSON 结构数据,说明接口是可以访问的。

打开WireShark工具,追踪一下POSTMAN访问的流数据,以及服务器返回的响应报文数据。

请求数据的追踪

接口返回的报文数据追踪

基础准备工作已经做好,那么STM32 W5500 Http Client POST请求的实现,由于一些信息比较敏感,对代码做了处理:

httppost.c

#ifndef __HTTPPOST_H
#define __HTTPPOST_H
#include "httppost.h"
#endif

u16 func_pack_httppost_body(char *buff_body, char *productId, char *deviceSn, char *deviceMac, char *devicePassword, char *hardwareVersion)
{
	u16 len;
	len = sprintf(buff_body, "a=%s&b=%s&c=%s&d=%s&e=%s",\
		productId, deviceSn, deviceMac, devicePassword, hardwareVersion);
	return len;
}

u16 func_pack_httppost_head_body(char *buff_post, char *url_tail, u8 *host, u16 port, char *body, u16 body_len)
{
	u16 len;
	len = sprintf(buff_post, "POST %s HTTP/1.1\r\n"
		"Connection: close\r\n"
		"User-Agent:W5500\r\n"
		"Content-Type:application/x-www-form-urlencoded\r\n"
		"Host: %d.%d.%d.%d:%d\r\n"
		"Content-Length: %d\r\n\r\n"
		"%s\r\n", url_tail, host[0], host[1], host[2], host[3], port, body_len, body
	);
	return len;
}

static u16 local_port = 50000;

u8 func_http_post(u8 sock_no, u8 *rip, u16 port, char *buf_post, u16 len_post,char *buf_recv, u16 *len_recv, u16 timeout_ms)
{
	u16 cnt, len;	
	char *body_cont;
	cnt = 0;
	
	for(;;)
	{
		switch(getSn_SR(sock_no))
		{
			case SOCK_INIT:
				connect(sock_no, rip, port);
			break;
			case SOCK_ESTABLISHED:
				send(sock_no, (u8*)buf_post, len_post); 
				if(getSn_IR(sock_no) & Sn_IR_CON)   					
				{
					setSn_IR(sock_no, Sn_IR_CON);
				}
				len = getSn_RX_RSR(sock_no);
				if(len > 0)
				{
					memset(buf_recv, 0, len_post);
					len = recv(sock_no, (u8*)buf_recv, len);
					body_cont = strstr((char*)buf_recv, "HTTP/1.1 200");
					if(body_cont == NULL)
					{
						return 2;
					}
					body_cont = strstr((char*)buf_recv, "\r\n\r\n");
					if(body_cont != NULL)
					{
						len = strlen(body_cont) - 4;
						memcpy(buf_recv, body_cont + 4, len);
						buf_recv[len] = '\0';
						*len_recv = len;
						close(sock_no);
						return 0;
					}					
				}				
			break;
			case SOCK_CLOSE_WAIT:
				close(sock_no);
			break;
			case SOCK_CLOSED:
				socket(sock_no, Sn_MR_TCP, local_port++, Sn_MR_ND);
				if(local_port > 64000)
				{
					local_port = 50000;
				}
			break;
		}
		
		cnt ++;
		if(cnt >= timeout_ms)
		{
			close(sock_no);
			return 1;
		}
		delay_ms(1);
	}
}

测试的主函数代码:

#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 __Z_HARDWARE_USART2_H
#define __Z_HARDWARE_USART2_H
#include "z_hardware_usart2.h"
#endif

#include "w5500.h"
#include "socket.h"
#include "w5500_conf.h"
#include "dhcp.h"
#include "dns.h"

#ifndef __HTTPPOST_H
#define __HTTPPOST_H
#include "httppost.h"
#endif

char buf_send[2048];
char buf_cont[256];
	
int main(void)
{
	DHCP_Get dhcp_get;
//	u8 buf_recv[1536] = {0, };
	
	u16 len, recv_len;
	u8 res;
	
	uint8 mac[6];
	u8 remote_ip[4] = {192, 168, 1, 109};
	u16 port = 8084;	
	
	init_led();
	
	init_system_spi();
	func_w5500_reset();
	
	init_hardware_usart2_dma(115200);
		
	getMacByLockCode(mac);
	setSHAR(mac);
	
	sysinit(txsize, rxsize);
	setRTR(2000);
  setRCR(3);
	
	//USART DMA problem 2byte missing
	func_usart2_dma_send_bytes(mac, 2);
	delay_ms(100);
	
	//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);
	}
	
	len = func_pack_httppost_body(buf_cont, "", "", "", "", "");
	
//	pack http message		
	len = func_pack_httppost_head_body(buf_send, "/a/b/c/d/create", remote_ip, port, buf_cont, len);
	
//	res = func_httpc_post(0, remote_ip, port, buf_send, len, buf_send, &recv_len, 1000, 5000);
	res = func_http_post(0, remote_ip, port, buf_send, len, buf_send, &recv_len, 1000);
	if(res == 0)
	{
		func_usart2_dma_send_bytes((u8*)buf_send, recv_len);
	}

	for(;;)
	{
		
		func_led1_on();
		delay_ms(1000);
		func_led1_off();
		delay_ms(1000);
		
	}
}

测试的结果,解析报文的body,并通过串口打印出来:

通过16进制转字符串转换一下,看看结果

 

物联网项目实战开发是一个复杂而有挑战性的任务,使用stm32 w5500以太网rj45进行数据上传至onenet物联网平台是其中的一种常见方案。下面是一个基于该方案的代码示例: ```C #include <SPI.h> #include <Ethernet.h> byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // MAC地址 IPAddress ip(192, 168, 1, 10); // 设备IP地址 EthernetClient client; void setup() { Ethernet.begin(mac, ip); Serial.begin(9600); delay(1000); } void loop() { if (client.connect("api.heclouds.com", 80)) { // 连接onenet物联网平台 String data = "data"; // 上传的数据,可根据需求自定义 client.println("POST /devices/{设备ID}/datapoints?type=3 HTTP/1.1"); // 替换为自己的设备ID client.println("Host: api.heclouds.com"); client.println("api-key: {API鉴权KEY}"); // 替换为自己的API鉴权KEY client.println("Content-Type: application/json"); String requestBody = "{\"datastreams\": [{\"id\": \"data\",\"datapoints\":[{\"value\": \"" + data + "\"}]}]}"; client.print("Content-Length: "); client.println(requestBody.length()); client.println(); client.println(requestBody); delay(1000); client.stop(); } else { Serial.println("无法连接到onenet物联网平台"); } delay(5000); // 每隔5秒上传一次数据,可根据需求调整 } ``` 以上代码通过使用Ethernet库进行以太网通信,设备连接到onenet物联网平台(API地址为api.heclouds.com)。在`loop()`函数中,首先与平台进行连接,然后构造要上传的数据,通过POST请求数据上传至onenet物联网平台。需要替换的部分包括设备ID和API鉴权KEY,确保与onenet平台的配置一致。 这段代码是一个基础框架,可以根据具体需求进行进一步的开发和扩展。希望这能帮助到你。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值