当前位置: 首页 > news >正文

测试W5500的第7步_使用ioLibrary库创建HTTP客户端

本文介绍了基于STM32和W5500芯片的HTTP通信开发过程。主要内容包括:1)HTTP测试工具httpbin的使用说明;2)W5500硬件初始化与SPI接口配置;3)DNS域名解析功能实现;4)HTTP客户端功能开发。通过实际测试,成功实现了域名解析、HTTP GET/POST请求等功能,验证了系统的可用性。测试结果显示,设备能正确获取IP地址信息,并能通过HTTP协议与远程服务器进行数据交互。文中详细提供了各功能模块的代码实现思路和关键配置参数,为嵌入式网络通信开发提供了实用参考。

做网络通讯,首先要找到合适的测试工具。

1、http测试工具:httpbin
http://k8s-pmhttpbi-pmhttpbi-4b5623588d-1738525105.us-east-1.elb.amazonaws.com
官方网站:http://httpbin.org,如果测试HTTPS,则访问https://httpbin.org
httpbin.org可以测试HTTP请求和响应等各种信息,比如cookie、ip、headers和登录验证等,且支持 GET、POST 等多种方法,对web开发和测试很有帮助。我们只是测试,对于这个HTTP测试页面,只需了解一下即可。

2、HTTP方法
1)、DELETE: /delete,删除请求的删除参数,The request's DELETE parameters.
2)、GET: /get,获取请求的查询参数,The request's query parameters.
3)、PATCH: /patch,给请求的补丁参数打补丁,The request's PATCH parameters.
4)、POST: /post,请求的POST参数,The request's POST parameters.
5)、PUT: /put,请求的PUT参数,The request's PUT parameters.
我们重点学习GET和POST,其次是学习DNS功能,DNS是Domain Name System,域名系统,用于将我们输入的网址转换为计算机能识别的IP地址。
正向DNS查询:将域名转换为IP地址的过程。

用法区别:

可以在计算机的URL栏里输入"http://httpbin.org/ip"测试,这和W5500的测试有点区别。

W5500发送"GET /ip\r\nHost: httpbin.org\r\n\r\n",接收到的数据如下
{
  "origin": "112.26.166.6"

使用网路调试助手测试HTTP客户端

3、ioLibrary库下载地址
下载地址:https://gitee.com/wiznet-hk/STM32F10x_W5500_Examples
源文件下载地址:https://gitee.com/wiznet-hk

4、wiz_platform.c

#include "wiz_platform.h"
#include <stdio.h>
#include <stdint.h>
#include "wizchip_conf.h"
#include "wiz_interface.h"
#include "stm32f10x.h"
#include "delay.h"
#include "dns.h"//函数功能:SPI1初始化
void wiz_spi_init(void)
{GPIO_InitTypeDef 	GPIO_InitStructure;SPI_InitTypeDef   SPI_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA的外设时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);  //使能SPI1的外设时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;         //选择PIN5,是SPI1的SCLGPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	  //选择引脚为复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚的最高工作速率为50MHzGPIO_Init(GPIOA, &GPIO_InitStructure);  //根据GPIO_InitStructure结构指针所指向的参数配置PA5引脚	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;         //选择PIN6,是SPI1的MISOGPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;	  //选择引脚为输入悬浮GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚的最高工作速率为50MHzGPIO_Init(GPIOA, &GPIO_InitStructure);  //根据GPIO_InitStructure结构指针所指向的参数配置PA6引脚GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;         //选择PIN7,是SPI1的MOSIGPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	  //选择引脚为复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚的最高工作速率为50MHzGPIO_Init(GPIOA, &GPIO_InitStructure);  //根据GPIO_InitStructure结构指针所指向的参数配置PA7引脚GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;         //选择PIN3,是W5500的片选脚CSGPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //选择引脚为推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚的最高工作速率为50MHzGPIO_Init(GPIOA, &GPIO_InitStructure);  //根据GPIO_InitStructure结构指针所指向的参数配置PA3引脚//设置SPI1的工作模式SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//SPI设置为双线双向全双工SPI_InitStructure.SPI_Mode = SPI_Mode_Master;     //设置为主SPISPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI发送接收为8位帧结构SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;        //设置SCK空闲时钟为低电平SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;      //数据捕获于第1个时钟沿//SCK空闲时钟为低电平,数据捕获于第1个时钟沿,这样就设置了SPI从机在下降沿采集数据了//SPI从机在下降沿采集数据,这要求CPU必须在SCK上升沿输出位值,在SCK为高电平时达到稳定,为数据采集做好准备SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;  //设置NSS输出由SSI位控制SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;//设置波特率预分频值为2SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;  //设置数据传输先从MSB位开始SPI_InitStructure.SPI_CRCPolynomial = 7;            //使用CRC7校验SPI_Init(SPI1, &SPI_InitStructure);SPI_Cmd(SPI1, ENABLE); //使能SPI外设
}//函数功能:初始化W5500的RST引脚和INT引脚
void wiz_rst_int_init(void)
{GPIO_InitTypeDef  GPIO_InitStructure;RCC_APB2PeriphClockCmd ( RCC_APB2Periph_GPIOC, ENABLE ); //使能GPIOC外设的高速时钟/* W5500_RST引脚初始化配置(PC5) */GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_5;	//选择PC5为W5500的RST引脚GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOC, &GPIO_InitStructure);GPIO_ResetBits(GPIOC, GPIO_Pin_5);RCC_APB2PeriphClockCmd ( RCC_APB2Periph_GPIOC, ENABLE ); //使能GPIOC外设的高速时钟/* W5500_INT引脚初始化配置(PC4) */	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;	//选择PC4为W5500的INT引脚GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(GPIOC, &GPIO_InitStructure);
}//函数功能:使能SPI片选
void wizchip_select(void)
{GPIO_ResetBits(GPIOA,GPIO_Pin_4);//输出低电平表示选择W5500
}//函数功能:不使能SPI片选
void wizchip_deselect(void)
{GPIO_SetBits(GPIOA,GPIO_Pin_4);//输出高电平表示不选择W5500
}//函数功能:通过SPI,将dat的值发送给W5500
void wizchip_write_byte(uint8_t dat)
{while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){//检查SPI1的发送完成标志是否建立}SPI_I2S_SendData(SPI1, dat);//通过SPI,将dat发送给W5500while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){//检查SPI1的接收完成标志是否建立}SPI_I2S_ReceiveData(SPI1);//读SPI接收数据寄存器
}//函数功能:通过SPI读取1个字节,并返回
uint8_t wizchip_read_byte(void)
{while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){//检查SPI1的发送完成标志是否建立}SPI_I2S_SendData(SPI1,0xffff);//发送16个移位时钟,为接收数据作准备while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){//检查SPI1的接收完成标志是否建立}return SPI_I2S_ReceiveData(SPI1);//读SPI接收数据寄存器
}//函数功能:通过SPI,将buf[]中的前len个字节发送给W5500
void wizchip_write_buff(uint8_t *buf, uint16_t len)
{uint16_t idx = 0;for (idx = 0; idx < len; idx++){wizchip_write_byte(buf[idx]);//通过SPI,将buf[idx]的值发送给W5500}
}//函数功能:通过SPI读取len个字节,保存到buf[]中
void wizchip_read_buff(uint8_t *buf, uint16_t len)
{uint16_t idx = 0;for (idx = 0; idx < len; idx++){buf[idx] = wizchip_read_byte();//通过SPI读取1个字节,保存到buf[idx]中}
}//函数功能:W5500使用RST引脚复位
void wizchip_reset(void)
{GPIO_SetBits(GPIOC, GPIO_Pin_5);//复位引脚拉高delay_ms(10);GPIO_ResetBits(GPIOC, GPIO_Pin_5);//复位引脚拉低delay_ms(10);GPIO_SetBits(GPIOC, GPIO_Pin_5);//复位引脚拉高delay_ms(10);
}//函数功能:注册SPI片选函数,单字节读写函数和多字节读写函数
//1.注册SPI片选信号函数
//2.注册SPI读写单一字节函数
//3.注册SPI读写多字节函数
void wizchip_spi_cb_reg(void)
{reg_wizchip_cs_cbfunc(wizchip_select, wizchip_deselect);//注册SPI片选信号函数reg_wizchip_spi_cbfunc(wizchip_read_byte, wizchip_write_byte);//注册SPI读写单一字节函数reg_wizchip_spiburst_cbfunc(wizchip_read_buff, wizchip_write_buff);//注册SPI读写多字节函数
}//函数功能:配置TIM2每毫秒中断一次
void wiz_timer_init(void)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);TIM_TimeBaseStructure.TIM_Period = 1000 - 1;TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1;TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);TIM_ClearFlag(TIM2, TIM_FLAG_Update);TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);TIM_Cmd(TIM2, ENABLE);
}//函数功能:使能TIM2中断
void wiz_tim_irq_enable(void)
{TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
}//函数功能:不使能TIM2中断
void wiz_tim_irq_disable(void)
{TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE);
}//函数功能:TIM2每毫秒中断一次
void TIM2_IRQHandler(void)
{static uint32_t wiz_timer_1ms_count = 0;if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){wiz_timer_1ms_count++;if (wiz_timer_1ms_count >= 1000){wiz_timer_1ms_count = 0;DNS_time_handler();}TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
}

5、wiz_interface.c

#include "wiz_interface.h"
#include "wiz_platform.h"
#include "wizchip_conf.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "delay.h"
#include "W5500_Variable.h"
#include "socket.h"void wizchip_initialize(void);
void UDP_network_init(uint8_t *ethernet_buff, wiz_NetInfo *conf_info);void wizchip_version_check(void);
void print_network_information(void);
void wiz_phy_link_check(void);
void wiz_print_phy_info(void);#define W5500_VERSION 0x04
//函数功能:读取芯片版本号码,并检查是否正确
void wizchip_version_check(void)
{uint8_t error_count = 0;while (1){delay_ms(1000);if (getVERSIONR() != W5500_VERSION){//读取芯片版本号码error_count++;if (error_count > 5){printf("error, %s version is 0x%02x, but read %s version value = 0x%02x\r\n", _WIZCHIP_ID_, W5500_VERSION, _WIZCHIP_ID_, getVERSIONR());while (1);}}else{break;}}
}/*** @brief Print PHY information*/
//函数功能:
//1.读PHY配置寄存器的bit1和bit2
//2.串口输出当前网速为100M/10M
//3.串口输出当前以太网采用全双工通讯/半双工通讯
void wiz_print_phy_info(void)
{uint8_t get_phy_conf;get_phy_conf = getPHYCFGR();//读PHY配置寄存器printf("The current Mbtis speed : %dMbps\r\n", get_phy_conf & 0x02 ? 100 : 10);//PHY配置寄存器,bit1=1表示网速为100M,bit1=0表示网速为10Mprintf("The current Duplex Mode : %s\r\n", get_phy_conf & 0x04 ? "Full-Duplex" : "Half-Duplex");//PHY配置寄存器,bit2=1表示以太网采用全双工通讯,bit2=0表示以太网采用半双工通讯
}//函数功能:
//读PHY配置寄存器的bit[2:0]
//bit0=1表示W5500连接到局域网
//bit1=1表示当前网速为100M,否则为10M
//bit2=1表示当前以太网采用全双工通讯,否则为半双工通讯
void wiz_phy_link_check(void)
{uint8_t phy_link_status;do{delay_ms(1000);ctlwizchip(CW_GET_PHYLINK, (void *)&phy_link_status);//读PH配置寄存器的bit0,保存到phy_link_status中,为1表示连接到局域网if (phy_link_status == PHY_LINK_ON){//W5500连接到局域网printf("PHY link\r\n");wiz_print_phy_info();//1.读PHY配置寄存器的bit1和bit2//2.串口输出当前网速为100M/10M//3.串口输出当前以太网采用全双工通讯/半双工通讯}else{printf("PHY no link\r\n");}} while (phy_link_status == PHY_LINK_OFF);
}//1.注册SPI片选函数,单字节读写函数和多字节读写函数
//2.W5500使用RST引脚复位
//3.读取芯片版本号码,并检查是否正确
//4.读PHY配置寄存器的bit[2:0],bit0=1表示W5500连接到局域网
//bit1=1表示当前网速为100M,否则为10M
//bit2=1表示当前以太网采用全双工通讯,否则为半双工通讯
void wizchip_initialize(void)
{wizchip_spi_cb_reg();//注册SPI片选函数,单字节读写函数和多字节读写函数wizchip_reset();//W5500使用RST引脚复位wizchip_version_check();//读取芯片版本号码,并检查是否正确//Read version registerwiz_phy_link_check();//读PHY配置寄存器的bit[2:0]//bit0=1表示W5500连接到局域网//bit1=1表示当前网速为100M,否则为10M//bit2=1表示当前以太网采用全双工通讯,否则为半双工通讯
}//函数功能:读本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP,然后从串口输出
void print_network_information(void)
{wiz_NetInfo net_info;wizchip_getnetinfo(&net_info);// Get chip configuration information//读本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCPif (net_info.dhcp == NETINFO_DHCP){printf("====================================================================================================\r\n");printf(" %s network configuration : DHCP\r\n\r\n", _WIZCHIP_ID_);}else{printf("====================================================================================================\r\n");printf(" %s network configuration : static\r\n\r\n", _WIZCHIP_ID_);}printf(" MAC         : %02X:%02X:%02X:%02X:%02X:%02X\r\n", net_info.mac[0], net_info.mac[1], net_info.mac[2], net_info.mac[3], net_info.mac[4], net_info.mac[5]);printf(" IP          : %d.%d.%d.%d\r\n", net_info.ip[0], net_info.ip[1], net_info.ip[2], net_info.ip[3]);printf(" Subnet Mask : %d.%d.%d.%d\r\n", net_info.sn[0], net_info.sn[1], net_info.sn[2], net_info.sn[3]);printf(" Gateway     : %d.%d.%d.%d\r\n", net_info.gw[0], net_info.gw[1], net_info.gw[2], net_info.gw[3]);printf(" DNS         : %d.%d.%d.%d\r\n", net_info.dns[0], net_info.dns[1], net_info.dns[2], net_info.dns[3]);printf("====================================================================================================\r\n\r\n");
}//函数功能:设置本地网络信息
//1.使用"默认网络参数"设置本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP
//2.读本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP,然后从串口输出
void TCP_network_init(uint8_t *ethernet_buff, wiz_NetInfo *conf_info)
{wizchip_setnetinfo(conf_info);//设置本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP模式print_network_information();//读本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP模式,然后从串口输出
}

6、W5500_Variable.c

#include "W5500_Variable.h"
#include "socket.h"	// Just include one header for WIZCHIP
#include "stdio.h"  //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()
#include "string.h" //使能strcpy(),strlen(),memset()//W5500的网络参数
//本地物理地址:00 08 DC 11 11 11
//本地IP地址:192.168.1.199
//本地子网掩码:	255.255.255.0
//本地网关:192.168.1.1
//DNS服务器IP地址:8.8.8.8
//程序固化IP地址
/* network information */
wiz_NetInfo net_info = {{0x00, 0x08, 0xdc,0x11, 0x11, 0x11},{192, 168, 1, 199},{255,255,255,0},{192, 168, 1, 1},{8,8,8,8},//DNS服务器IPNETINFO_STATIC}; //静态IP,程序固化IP地址
wiz_NetInfo net_info;uint16_t LocalPort=4000;//W5500的本地端口uint8_t ethernet_buf[ETHERNET_BUF_MAX_SIZE] = {0};uint8_t org_server_name[] = "httpbin.org";//默认域名为"httpbin.org"
/*
http测试工具:httpbin
http://k8s-pmhttpbi-pmhttpbi-4b5623588d-1738525105.us-east-1.elb.amazonaws.com
官方网站:http://httpbin.org,如果测试HTTPS,则访问https://httpbin.org
开源地址:https://github.com/Runscope/httpbin
httpbin.org可以测试HTTP请求和响应等各种信息,比如cookie、ip、headers和登录验证等,
且支持 GET、POST 等多种方法。对web开发和测试很有帮助。
使用介绍https://www.cnblogs.com/wzihan/p/17484966.html
*/
uint8_t org_server_ip[4] = {0}; /*用来保存解析域名httpbin.org得到的IP地址*/
uint16_t org_port = 80;          /*httpbin.org的端口,必须是已知的*/

7、Do_DNS.c

#include "Do_DNS.h"
#include <stdio.h>
#include "socket.h"
#include "wizchip_conf.h"
#include "W5500_Variable.h"
#include <string.h>
#include "dns.h"int do_dns(uint8_t *buf, uint8_t *domain_name, uint8_t *domain_ip);/*** @brief   DNS domain name resolution* @param   ethernet_buff: ethernet buffer* @param   domain_name:Domain name to be resolved* @param   domain_ip:Resolved Internet Protocol Address* @return  0:success;-1:failed*///函数功能:根据域名domain_name[],通过DNS解析到IP地址,保存到domain_ip[]//buf[]用作接收缓冲区;
int do_dns(uint8_t *buf, uint8_t *domain_name, uint8_t *domain_ip)
{int dns_ok_flag = 0;int dns_run_flag = 1;wiz_NetInfo net_info;uint8_t dns_retry_cnt = 0;DNS_init(0, buf); //DNS客户端初始化wizchip_getnetinfo(&net_info);//读本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCPwhile (1){switch (DNS_run(net_info.dns, domain_name, domain_ip)) // Read the DNS_run return value{case DNS_RET_FAIL: // The DNS domain name is successfully resolved{if (dns_retry_cnt < DNS_RETRY) // Determine whether the parsing is successful or whether the parsing exceeds the number of times{dns_retry_cnt++;}else{printf("> DNS Failed\r\n");dns_ok_flag = -1;dns_run_flag = 0;}break;}case DNS_RET_SUCCESS://"域名解析"成功{printf("> Translated %s to %d.%d.%d.%d\r\n", domain_name, domain_ip[0], domain_ip[1], domain_ip[2], domain_ip[3]);dns_ok_flag = 0;dns_run_flag = 0;break;}}if (dns_run_flag != 1){return dns_ok_flag;}}
}

8、Test_httpclient.c

#include "Test_httpclient.h"
#include <stdio.h>
#include "socket.h"
#include "wizchip_conf.h"
#include "W5500_Variable.h"
#include <string.h>
#include <stdlib.h>
#include "delay.h"uint32_t http_get_IP(uint8_t *pkt);
uint32_t http_post_OperateData(uint8_t *pkt,char *op);
uint32_t http_get_OperateData(uint8_t *pkt,char *op);//uint32_t http_get_pkt(uint8_t *pkt);
//uint32_t http_post_pkt(uint8_t *pkt);
uint8_t  do_http_request(uint8_t sn, uint8_t *buf, uint16_t len, uint8_t *destip, uint16_t destport);//函数功能:HTTP GET,生成"请求软件包组合包",Request package combination package.
//返回值为pkt[]中的字符串长度
//pkt:用于分组的软件包的数组高速缓存
//httpbin.org工具中有"GET /ip"命令,用来返回请求者的IP地址。
/*
在计算机的URL栏里输入"https://httpbin.org/ip"
在计算机的URL栏里输入"http://httpbin.org/ip",接收数据如下:
{"origin": "112.26.166.6"
}
*/
/*
W5500发送"GET /ip\r\nHost: httpbin.org\r\n\r\n",接收到的数据如下
{"origin": "112.26.166.6"
}
*/
const char GET_IP_REG[]="GET /ip\r\n";
const char Host_REG[]="Host: ";
const char Host_rn_REG[]="\r\n";
uint32_t http_get_IP(uint8_t *pkt)
{*pkt = 0;strcat((char *)pkt, GET_IP_REG);//添加"GET /ip\r\n",request type URL HTTP protocol versionstrcat((char *)pkt, Host_REG);                //添加"Host: "strcat((char *)pkt, (char*)org_server_name);  //添加"httpbin.org"strcat((char *)pkt, Host_rn_REG);             //添加"/r/n"//添加内容为"Host: httpbin.org\r\n"//主机地址可以是一个域名或一个特定的IP地址;Host address, which can be a domain name or a specific IP address.strcat((char *)pkt, Host_rn_REG);//pkt[]="GET /ip\r\nHost: httpbin.org\r\n\r\n"return strlen((char *)pkt);
}//函数功能:HTTP POST,生成"请求软件包组合包",Request package combination package.
//返回值为pkt[]中的字符串长度
//pkt:用于分组的软件包的数组高速缓存
const char POST_REG[]="POST /post HTTP/1.1\r\n";
const char Content_Type_REG[]="Content-Type:application/x-www-form-urlencode\r\n";
const char Content_Length_REG[]="Content-Length:";
//pkt[]="POST /post HTTP/1.1\r\nHost: httpbin.org\r\nContent-Type:application/x-www-form-urlencode\r\nContent-Length:29\r\n\r\nusername=admin&password=admin"
uint32_t http_post_OperateData(uint8_t *pkt,char *op)
{uint8_t len;char buf[20];len=strlen(op);sprintf(buf,"%u",len);*pkt = 0;strcat((char *)pkt, POST_REG);//添加"POST /post HTTP/1.1\r\n",request type URL HTTP protocol versionstrcat((char *)pkt, Host_REG);                //添加"Host: "strcat((char *)pkt, (char*)org_server_name);  //添加"httpbin.org"strcat((char *)pkt, Host_rn_REG);             //添加"/r/n"//添加内容为"Host: httpbin.org\r\n"//主机地址可以是一个域名或一个特定的IP地址;Host address, which can be a domain name or a specific IP address.strcat((char *)pkt, Content_Type_REG);//主要内容格式,Main content formatstrcat((char *)pkt, Content_Length_REG);//添加"Content-Length:"strcat((char *)pkt, buf);//主要内容长度,Main content lenghtstrcat((char *)pkt, Host_rn_REG);//分离,separatorstrcat((char *)pkt, Host_rn_REG);//分离,separatorstrcat((char *)pkt, op);//添加主要内容,main contentreturn strlen((char *)pkt);
}//函数功能:HTTP GET,生成"请求软件包组合包",Request package combination package.
//返回值为pkt[]中的字符串长度
//pkt:用于分组的软件包的数组高速缓存
const char GET_REG[]="GET /get?";
const char HTTP_1_1_REG[]=" HTTP/1.1\r\n";
uint32_t http_get_OperateData(uint8_t *pkt,char *op)
{*pkt = 0;strcat((char *)pkt, GET_REG);//添加"GET /get?",request type URL HTTP protocol versionstrcat((char *)pkt, op);strcat((char *)pkt, HTTP_1_1_REG);//添加" HTTP/1.1\r\n"strcat((char *)pkt, Host_REG);                //添加"Host: "strcat((char *)pkt, (char*)org_server_name);  //添加"httpbin.org"strcat((char *)pkt, Host_rn_REG);             //添加"/r/n"//添加内容为"Host: httpbin.org\r\n"//主机地址可以是一个域名或一个特定的IP地址;Host address, which can be a domain name or a specific IP address.strcat((char *)pkt, Host_rn_REG);//添加"发送结束符"return strlen((char *)pkt);
}//函数功能:HTTP客户端获取数据流,HTTP Client get data stream.
//返回值为0,表示超时,返回值为1表示接收到应答数据
//sn为SOCKET通道号码
//buf[]为请求消息内容,request message content
//len为请求消息的长度,request message length
//destip[]为目的IP地址,destion ip
//destport为目的端口destion port
uint8_t do_http_request(uint8_t sn, uint8_t *buf, uint16_t len, uint8_t *destip, uint16_t destport)
{uint16_t recv_timeout = 0;//超时计数器uint8_t  send_flag    = 0;//建立发送标志while (1){switch (getSn_SR(sn)){case SOCK_INIT:// Connect to http server.connect(sn, destip, destport);break;case SOCK_ESTABLISHED:if (send_flag == 0)//只执行一次"发送请求"{// send requestsend(sn, buf, len);send_flag = 1;//取消建立发送标志printf("send request:\r\n");for (uint16_t i = 0; i < len; i++){printf("%c", *(buf + i));}printf("\r\n");}//响应内容处理,Response content processinglen = getSn_RX_RSR(sn);//读SOCKET通道sn接收缓冲区的数据长度if (len > 0)//接收到来自外网的数据{printf("Receive response:\r\n");while (len > 0){len = recv(sn, buf, len);//读"SOCKET通道sn"的数据,长度为len个字节,保存到buf[]for (uint16_t i = 0; i < len; i++){printf("%c", *(buf + i));}len = getSn_RX_RSR(sn);//读SOCKET通道sn接收缓冲区的数据长度}printf("\r\n");disconnect(sn);//断开"SOCKET通道sn"的连接close(sn);     //关闭"SOCKET通道sn"return 1;}else{recv_timeout++;//超时计数器加1delay_ms(1000);}if (recv_timeout > 10)//出现超时{printf("request fail!\r\n");disconnect(sn);//断开"SOCKET通道sn"的连接close(sn);     //关闭"SOCKET通道sn"return 0;}break;case SOCK_CLOSE_WAIT://如果出现请求错误,服务器将立即发送关闭请求,所以在这里需要处理错误响应的内容。len = getSn_RX_RSR(sn);//读SOCKET通道sn接收缓冲区的数据长度if (len > 0){printf("Receive response:\r\n");while (len > 0){len = recv(sn, buf, len);//读"SOCKET通道sn"的数据,长度为len个字节,保存到buf[]for (uint16_t i = 0; i < len; i++){printf("%c", *(buf + i));}len = getSn_RX_RSR(sn);//读SOCKET通道sn接收缓冲区的数据长度}printf("\r\n");disconnect(sn);//断开"SOCKET通道sn"的连接close(sn);     //关闭"SOCKET通道sn"return 1;}close(sn);//关闭"SOCKET通道sn"break;case SOCK_CLOSED:close(sn);//关闭"SOCKET通道sn",close socketsocket(sn, Sn_MR_TCP, LocalPort, 0x00);//打开"SOCKET通道sn",打开一个本地端口,open socketbreak;default:break;}}
}/*
//函数功能:HTTP GET,生成"请求软件包组合包",Request package combination package.
//返回值为pkt[]中的字符串长度
//pkt:用于分组的软件包的数组高速缓存,Array cache for grouping packages
//pkt[]="GET /get?username=admin&password=admin HTTP/1.1\r\nHost: httpbin.org\r\n\r\n"
uint32_t http_get_pkt(uint8_t *pkt)
{*pkt = 0;// request type URL HTTP protocol versionstrcat((char *)pkt, "GET /get?username=admin&password=admin HTTP/1.1\r\n");// Host address, which can be a domain name or a specific IP address.strcat((char *)pkt, "Host: httpbin.org\r\n");// endstrcat((char *)pkt, "\r\n");return strlen((char *)pkt);
}//函数功能:HTTP POST,生成"请求软件包组合包",Request package combination package.
//返回值为pkt[]中的字符串长度
//pkt:用于分组的软件包的数组高速缓存,Array cache for grouping packages
//pkt[]="POST /post HTTP/1.1\r\nHost: httpbin.org\r\nContent-Type:application/x-www-form-urlencode\r\nContent-Length:29\r\n\r\nusername=admin&password=admin"
uint32_t http_post_pkt(uint8_t *pkt)
{*pkt = 0;// request type URL HTTP protocol versionstrcat((char *)pkt, "POST /post HTTP/1.1\r\n");// Host address, which can be a domain name or a specific IP address.strcat((char *)pkt, "Host: httpbin.org\r\n");// Main content formatstrcat((char *)pkt, "Content-Type:application/x-www-form-urlencode\r\n");// Main content lenghtstrcat((char *)pkt, "Content-Length:29\r\n");// separatorstrcat((char *)pkt, "\r\n");// main contentstrcat((char *)pkt, "username=admin&password=admin");return strlen((char *)pkt);
}
*//*
HTTP方法
1)、DELETE: /delete,删除请求的删除参数,The request's DELETE parameters.
2)、GET: /get,获取请求的查询参数,The request's query parameters.
3)、PATCH: /patch,给请求的补丁参数打补丁,The request's PATCH parameters.
4)、POST: /post,请求的POST参数,The request's POST parameters.
5)、PUT: /put,请求的PUT参数,The request's PUT parameters.
我们重点学习GET和POST,其次是学习DNS功能,DNS是Domain Name System,域名系统,用于将我们输入的网址转换为计算机能识别的IP地址。
正向DNS查询:将域名转换为IP地址的过程。ioLibrary库下载地址
下载地址:https://gitee.com/wiznet-hk/STM32F10x_W5500_Examples
源文件下载地址:https://gitee.com/wiznet-hk
*/

9、Test_httpclient.h

#ifndef _Test_httpclient_H_
#define _Test_httpclient_H_#include <stdint.h>#define TCP_SOCKET0        0     //W5500使用端口0作为TCP
#define TCP_SOCKET1        1     //W5500使用端口1作为TCP
#define TCP_SOCKET2        2     //W5500使用端口2作为TCP
#define TCP_SOCKET3        3     //W5500使用端口3作为TCP
#define TCP_SOCKET4        4     //W5500使用端口4作为TCP
#define TCP_SOCKET5        5     //W5500使用端口5作为TCP
#define TCP_SOCKET6        6     //W5500使用端口6作为TCP
#define TCP_SOCKET7        7     //W5500使用端口7作为TCPextern uint32_t http_get_IP(uint8_t *pkt);
extern uint32_t http_post_OperateData(uint8_t *pkt,char *op);
extern uint32_t http_get_OperateData(uint8_t *pkt,char *op);extern uint8_t  do_http_request(uint8_t sn, uint8_t *buf, uint16_t len, uint8_t *destip, uint16_t destport);
//extern uint32_t http_get_pkt(uint8_t *pkt);
//extern uint32_t http_post_pkt(uint8_t *pkt);
#endif

10、main.c

#include "stm32f10x.h"//使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,int16_t,int32_t,int64_t
#include "stdio.h"  //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()
#include "string.h" //使能strcpy(),strlen(),memset()
#include "delay.h"
#include "USART4.h"
#include "LED.h"
#include "socket.h"//ioLibrary库下载地址
//下载地址:https://gitee.com/wiznet-hk/STM32F10x_W5500_Examples
//源文件下载地址:https://gitee.com/wiznet-hk
#include "wiz_platform.h"
#include "wizchip_conf.h"
#include "wiz_interface.h"
#include "W5500_Variable.h"
#include "Do_DNS.h"
#include "Test_httpclient.h"const char CPU_Reset_REG[]="\r\nCPU reset!\r\n";
int main(void)
{uint16_t len;//	SCB->VTOR = 0x8000000;//中断向量表重定义//	SystemInit();delay_init();//延时函数初始化NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4USART4_Serial_Interface_Enable(115200);printf("%s",CPU_Reset_REG);//调试串口输出"\r\nCPU reset!\r\n"LED_Init();LED0_ON();wiz_timer_init();  //配置TIM2每毫秒中断一次wiz_spi_init();    //SPI1初始化wiz_rst_int_init();//初始化W5500的RST引脚和INT引脚printf("%s network install example\r\n",_WIZCHIP_ID_);wizchip_initialize();//1.注册SPI片选函数,单字节读写函数和多字节读写函数//2.W5500使用RST引脚复位//3.读取芯片版本号码,并检查是否正确//4.读PHY配置寄存器的bit[2:0],bit0=1表示W5500连接到局域网//bit1=1表示当前网速为100M,否则为10M//bit2=1表示当前以太网采用全双工通讯,否则为半双工通讯TCP_network_init(ethernet_buf, &net_info);
//设置本地网络信息
//1.使用"默认网络参数"设置本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP模式
//2.读本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP模式,然后从串口输出socket(TCP_SOCKET0, Sn_MR_TCP, LocalPort, 0x00);//令SOCKET端口0工作在TCP模式,并设置TCP端口为LocalPort//这里使用SOCKET通道0作为TCP客户端或服务端if (do_dns(ethernet_buf, org_server_name, org_server_ip)){//根据域名org_server_namee[],通过DNS解析到IP地址,保存到org_server_ip[]printf("DNS request failed.\r\n");while (1){}}len = http_get_IP(ethernet_buf);//准备发送内容,使用GET命令查询"请求者的IP地址"do_http_request(TCP_SOCKET0, ethernet_buf, len, org_server_ip, org_port);//向IP地址和端口发送GET命令查询"请求者的IP地址"len = http_post_OperateData(ethernet_buf,"LED1=1&LED2=1");//准备发送内容,使用POST命令设置LED1=1,LED2=1do_http_request(TCP_SOCKET0, ethernet_buf, len, org_server_ip, org_port);//向IP地址和端口发送POST命令,令LED1=1,LED2=1len = http_get_OperateData(ethernet_buf,"LED1=1&LED2=0");//准备发送内容,使用GET命令查询LED1和LED2的值do_http_request(TCP_SOCKET0, ethernet_buf, len, org_server_ip, org_port);//向IP地址和端口发送GET命令查询LED1和LED2的值while(1){LED0=!LED0;delay_ms(1000);}
}

11、测试结果

[14:28:07.803]收←◆
CPU reset!

[14:28:08.315]收←◆W5500 network install example

[14:28:10.347]收←◆PHY link
The current Mbtis speed : 100Mbps
The current Duplex Mode : Full-Duplex
====================================================
 W5500 network configuration : static

 MAC         : 00:08:DC:11:11:11
 IP          : 192.168.1.199
 Subnet Mask : 255.255.255.0
 Gateway     : 192.168.1.1
 DNS         : 8.8.8.8
=====================================================

> Translated httpbin.org to 54.166.245.7

[14:28:10.710]收←◆send request:
GET /ip
Host: httpbin.org

[14:28:11.714]收←◆Receive response:
{
  "origin": "112.26.166.6"
}


[14:28:12.254]收←◆send request:
POST /post HTTP/1.1
Host: httpbin.org
Content-Type:application/x-www-form-urlencode
Content-Length:13

LED1=1&LED2=1

[14:28:13.267]收←◆Receive response:
HTTP/1.1 200 OK
Date: Mon, 26 May 2025 06:28:12 GMT
Content-Type: application/json
Content-Length: 360
Connection: keep-alive
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

{
  "args": {}, 
  "data": "LED1=1&LED2=1"
  "files": {}, 
  "form": {}, 
  "headers": {
    "Content-Length": "13", 
    "Content-Type": "application/x-www-form-urlencode", 
    "Host": "httpbin.org", 
    "X-Amzn-Trace-Id": "Root=1-683409fc-3a04b1b92594e6456a00d328"
  }, 
  "json": null, 
  "origin": "112.26.166.6", 
  "url": "http://httpbin.org/post"
}


[14:28:13.860]收←◆send request:
GET /get?LED1=1&LED2=0 HTTP/1.1
Host: httpbin.org

[14:28:14.869]收←◆Receive response:
HTTP/1.1 200 OK
Date: Mon, 26 May 2025 06:28:14 GMT
Content-Type: application/json
Content-Length: 248
Connection: keep-alive
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

{
  "args": {
    "LED1": "1", 
    "LED2": "0"
  }, 
  "headers": {
    "Host": "httpbin.org", 
    "X-Amzn-Trace-Id": "Root=1-683409fe-057ed2191c75a3ff6aeed62b"
  }, 
  "origin": "112.26.166.6", 
  "url": "http://httpbin.org/get?LED1=1&LED2=0"
}

相关文章:

  • 学习心得(14--16)
  • python打卡训练营打卡记录day37
  • day28:零基础学嵌入式之进程2
  • 轻量级视觉语言模型 Dolphin:高效精准的文档结构化解析利器
  • AI算力网络光模块市场发展分析
  • 202505系分论文《论模型驱动分析方法及应用》
  • 基于大模型的胃肠道功能紊乱手术全程预测与干预方案研究
  • 统一人体姿态估计与分割的新方法:KDC
  • 《DeepSeek行业应用全景指南(视频微课版)》:从入门到精通的AI落地实践手册
  • 身份认证: JWT和Session是什么?
  • 【Java】异常处理
  • 信息学奥赛一本通 1547:【 例 1】区间和
  • AlphaCore GPU 物理仿真引擎内测邀请
  • 高并发系统下Mutex锁、读写锁、线程重入锁的使用思考
  • JetsonHacksNano RealSense自动安装脚本文件解析
  • 《仿盒马》app开发技术分享-- 新增地址(端云一体)
  • TLS/PSK
  • Ubantu服务器上的LiberOffice桌面版(版本24.2.7.2)如何设置中文
  • 网络编程2
  • STM32H7系列USART驱动区别解析 stm32h7xx_hal_usart.c与stm32h7xx_ll_usart.c的区别?
  • 真人男女直接做的视频网站/西安seo外包服务
  • 南充网站建设/qq群推广网站免费
  • 用java做网页如何建立网站/英文站友情链接去哪里查
  • 每天做任务得钱的网站/找seo外包公司需要注意什么
  • 网站建设seo优化/企业网站多少钱一年
  • 二手网站建设/微信营销的模式有哪些