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

W5500使用ioLibrary库创建DHCP客户端

本文还绍了如何配置W5500的网络参数,并通过代码示例展示了如何初始化SPI接口、配置端口、实现DHCP获取在局域网中的本地IP地址。端口0配置为调试端口,端口1配置为DNS客户端,端口2配置DHCP客户端

W5500是一款全硬件TCP/IP以太网控制器。W5500集成了TCP/IP协议栈,10/100M以太网数据链路
层(MAC)及物理层(PHY),使得用户使用单芯片就能够在他们的应用中拓展网络连接。
支持8个独立端口(Socket)同时通讯,每个端口内嵌32K字节片上缓存以供以太网包处理。
W5500提供了SPI接口,最大支持80MHz速率,W5500支持SPI模式0和模式3。
ioLibrary库下载地址: https://gitcode.com/gh_mirrors/io/ioLibrary_Driver?utm_source=csdn_github_accelerator&isLogin=1

WIZnet全硬件TCP/IP协议栈,支持TCP,UDP,IPv4,ICMP,ARP,IGMP以及PPPoE协议。
以太网:支持BSD和WIZCHIP(W5500/W5300/W5200/W5100/W5100S)的SOCKET APIs驱动程序。
互联网:
DHCP客户端
DNS客户端
FTP客户端
FTP服务器
SNMP代理/陷阱
SNTP客户端
TFTP客户端
HTTP服务器
MQTT客户端
其他功能将陆续添加。
 

1、将端口0配置调试端口,端口1配置为DNS客户端,端口2配置DHCP客户端

#include "W5500_HD_Driver.h"        
#include "stdio.h"  //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()
#include "socket.h"    // Just include one header for WIZCHIP

#include "string.h" //使能strcpy(),strlen(),memset()
#include "dns.h"
#include "Timer2.h"
#include "dhcp.h"

//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地址
wiz_NetInfo gWIZNETINFO = { {0x00, 0x08, 0xdc,0x11, 0x11, 0x11},
                            {192, 168, 1, 199},
                            {255,255,255,0},
                            {192, 168, 1, 1},
                            {180,76,76,76},//百度的DNS服务器IP
                            NETINFO_DHCP };

//端口0的网络参数
uint16_t LocalPort0=5000;                   //端口0的本地端口号(5000)
uint8_t  DstIP_Port0[4]={192,168,1,190}; //端口0的远程IP地址:192.168.1.190
uint16_t DstPort_Port0=6000;             //端口0的远程端口号:6000

uint8_t gDATABUF[DATA_BUF_SIZE];//STM32接收/发送W5500的数据缓冲区

uint8_t domain_name[]="www.baidu.com";
uint8_t domain_ip[4]={0};//解析到的IP为"36.152.44.132"
uint8_t DNS_get_ip_flag;//DNS获取IP标志

uint8_t dhcp_get_ip_flag;//DHCP获取IP标志
#define DHCP_RETRY_COUNT 3  //DHCP重试次数计数器门槛值
uint8_t dhcp_retry;  //DHCP重试次数计数器

void W5500_SPI_Init(void);
void W5500_Initialization(void);
void SOCKET0_Work(void);
void SOCKET1_Work(void);
void SOCKET0_Send_Domain_IP(void);
void SOCKET0_Send_Local_Net_Parameters(void);
void DHCP_Initialization(void);
void SOCKET2_Work(void);

//函数功能:
//初始化SPI1_SCL为PA5,SPI1_MISO为PA6,SPI1_MOSI为PA7,SPI1_CS为PA3;
//设置SPI1的工作模式
void W5500_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的SCL
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;      //选择引脚为复用推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚的最高工作速率为50MHz
  GPIO_Init(GPIOA, &GPIO_InitStructure);  //根据GPIO_InitStructure结构指针所指向的参数配置PA5引脚    

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;         //选择PIN6,是SPI1的MISO
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;      //选择引脚为输入悬浮
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚的最高工作速率为50MHz
  GPIO_Init(GPIOA, &GPIO_InitStructure);  //根据GPIO_InitStructure结构指针所指向的参数配置PA6引脚

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;         //选择PIN7,是SPI1的MOSI
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;      //选择引脚为复用推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚的最高工作速率为50MHz
  GPIO_Init(GPIOA, &GPIO_InitStructure);  //根据GPIO_InitStructure结构指针所指向的参数配置PA7引脚

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;         //选择PIN3,是W5500的片选脚CS
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //选择引脚为推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚的最高工作速率为50MHz
  GPIO_Init(GPIOA, &GPIO_InitStructure);  //根据GPIO_InitStructure结构指针所指向的参数配置PA3引脚

//设置SPI1的工作模式
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    //SPI设置为双线双向全双工
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;     //设置为主SPI
  SPI_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;
    //设置波特率预分频值为2
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;  //设置数据传输先从MSB位开始
  SPI_InitStructure.SPI_CRCPolynomial = 7;            //使用CRC7校验
  SPI_Init(SPI1, &SPI_InitStructure);

  SPI_Cmd(SPI1, ENABLE); //使能SPI外设
}

//函数功能:选择W5500
void SPI_CS_Select(void)
{
    W5500_CS_low();
}

//函数功能:不选择W5500
void SPI_CS_Deselect(void)
{
    W5500_CS_high();
}

//函数功能:从W5500读取一个字节
uint8_t SPI_ReadByte(void)
{
    uint8_t byte;

    byte=SPI_I2S_ReceiveData(SPI1);//虚读一次
    SPI_I2S_SendData(SPI1,0x00);//通过外设SPI1发送0x00为的是发送8个移位时钟
    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    //检查SPI1标志位,是否设置"发送缓存空标志位",等待数据寄存器空
    byte=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据

    return byte;
}

//函数功能:将byte发送给W5500
void SPI_WriteByte(uint8_t byte)
{
    SPI_I2S_SendData(SPI1,byte);//通过外设SPI1发送一个数据
    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    //检查SPI1标志位,是否设置"发送缓存空标志位",等待数据寄存器空
}

//函数功能:关闭总中断
void SPI_CrisEnter(void)
{
    __set_PRIMASK(1);//关闭总中断
}

//函数功能:使能总中断
void SPI_CrisExit(void)
{
    __set_PRIMASK(0);//开放总中断
}

//函数功能:装载W5500的本地网络参数和端口0的网络参数
void W5500_Load_Net_Parameters(void)
{
//本地物理地址:00 08 DC 11 11 11
    gWIZNETINFO.mac[0]=0x00;
    gWIZNETINFO.mac[1]=0x08;
    gWIZNETINFO.mac[2]=0xdc;
    gWIZNETINFO.mac[3]=0x11;
    gWIZNETINFO.mac[4]=0x11;
    gWIZNETINFO.mac[5]=0x11;

//本地IP地址:192.168.1.199
    gWIZNETINFO.ip[0]=192;
    gWIZNETINFO.ip[1]=168;
    gWIZNETINFO.ip[2]=1;
    gWIZNETINFO.ip[3]=199;

//本地子网掩码:    255.255.255.0
    gWIZNETINFO.sn[0]=255;
    gWIZNETINFO.sn[1]=255;
    gWIZNETINFO.sn[2]=255;
    gWIZNETINFO.sn[3]=0;

//本地网关:192.168.1.1
  gWIZNETINFO.gw[0]=192;
    gWIZNETINFO.gw[1]=168;
    gWIZNETINFO.gw[2]=1;
    gWIZNETINFO.gw[3]=1;

//DNS服务器IP地址:8.8.8.8
  gWIZNETINFO.dns[0]=8;
    gWIZNETINFO.dns[1]=8;
    gWIZNETINFO.dns[2]=8;
    gWIZNETINFO.dns[3]=8;

//DHCP模式
  gWIZNETINFO.dhcp=NETINFO_DHCP;
    //告诉ioLibrary库,当前使用"动态IP地址"配置

//端口0的本地端口号
    LocalPort0=5000;

//端口0的远程IP地址:192.168.1.190
  DstIP_Port0[0]=192;
    DstIP_Port0[1]=168;
    DstIP_Port0[2]=1;
    DstIP_Port0[3]=190;

//端口0的远程端口号
  DstPort_Port0=6000;
}

/**
  * @brief  Intialize the network information to be used in WIZCHIP
  * @retval None
  */
//函数功能:设置本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP
void network_init(void)
{
  uint8_t tmpstr[6];
    ctlnetwork(CN_SET_NETINFO, (void*)&gWIZNETINFO);
    //设置本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP
    //设置MAC地址,将gWIZNETINFO.mac写入W5500;
    //设置网关,将gWIZNETINFO.gw写入W5500;
    //设置子网掩码,将gWIZNETINFO.sn写入W5500
    //设置本地IP地址,将gWIZNETINFO.ip写入W5500
    //将gWIZNETINFO.dns[]拷贝到_DNS_[]中
    //将gWIZNETINFO.dhcp保存到_DHCP_中

    ctlnetwork(CN_GET_NETINFO, (void*)&gWIZNETINFO);
    //读本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP
    //读MAC地址,保存到gWIZNETINFO.mac
    //读网关,保存到gWIZNETINFO.gw
    //读子网掩码,保存到gWIZNETINFO.sn
    //读本地IP地址,保存到gWIZNETINFO.ip
    //将_DNS_[]拷贝到gWIZNETINFO.dns[]中
    //将_DHCP_保存到gWIZNETINFO.dhcp中

    ctlwizchip(CW_GET_ID,(void*)tmpstr);
    //读W5500的ID,保存到tmpstr[6]中,"W5500\0",这是ioLibrary驱动定义的ID;
    //在wizchip_conf.h中定义_WIZCHIP_ID_为"W5500\0"

    printf("\r\n=== %s NET CONF ===\r\n",(char*)tmpstr);
    //串口输出W5500的ID

    printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n",gWIZNETINFO.mac[0],gWIZNETINFO.mac[1],gWIZNETINFO.mac[2],
    gWIZNETINFO.mac[3],gWIZNETINFO.mac[4],gWIZNETINFO.mac[5]);//串口输出W5500的MAC地址

    printf("SIP: %d.%d.%d.%d\r\n", gWIZNETINFO.ip[0],gWIZNETINFO.ip[1],gWIZNETINFO.ip[2],gWIZNETINFO.ip[3]);
    //串口输出W5500的IP地址

    printf("GAR: %d.%d.%d.%d\r\n", gWIZNETINFO.gw[0],gWIZNETINFO.gw[1],gWIZNETINFO.gw[2],gWIZNETINFO.gw[3]);
    //串口输出W5500的网关地址

    printf("SUB: %d.%d.%d.%d\r\n", gWIZNETINFO.sn[0],gWIZNETINFO.sn[1],gWIZNETINFO.sn[2],gWIZNETINFO.sn[3]);
    //串口输出W5500的子网掩码

    printf("DNS: %d.%d.%d.%d\r\n", gWIZNETINFO.dns[0],gWIZNETINFO.dns[1],gWIZNETINFO.dns[2],gWIZNETINFO.dns[3]);
    //串口输出W5500的DNS服务器IP地址
    printf("======================\r\n");
}

//函数功能:
//1.初始化SPI接口
//2.注册相关函数
//3.设置W5500每个端口的发送缓冲区和接收缓冲区的大小均为2K字节
//4.等待"以太网"连接完成
//5.装载本地网络参数
//6.设置本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP
void W5500_Initialization(void)
{
    uint8_t memsize[2][8] = {{2,2,2,2,2,2,2,2},{2,2,2,2,2,2,2,2}};
    //W5500发送和接收各有8个端口,这里定义每个端口的发送缓冲区和接收缓冲区的大小均为2K字节
    uint8_t tmp;

    W5500_SPI_Init();   //W5500 SPI初始化配置
//    W5500_RST_Init();      //W5500 RST引脚初始化
//    W5500_INT_Init();   //W5500 INT引脚初始化
//    W5500_Hardware_Reset();        //硬件复位W5500
    reg_wizchip_cris_cbfunc(SPI_CrisEnter, SPI_CrisExit);    //注册临界区函数
    reg_wizchip_cs_cbfunc(SPI_CS_Select, SPI_CS_Deselect);//注册SPI片选信号函数
    reg_wizchip_spi_cbfunc(SPI_ReadByte, SPI_WriteByte);    //注册读写函数

    if(ctlwizchip(CW_INIT_WIZCHIP,(void*)memsize) == -1)
    {//W5500发送和接收各有8个端口,这里初始化每个端口的发送缓冲区和接收缓冲区的大小均为2K字节
         printf("WIZCHIP Initialized fail.\r\n");
    }

    //等待"以太网"连接完成, PHY link status check
    do{
         if(ctlwizchip(CW_GET_PHYLINK, (void*)&tmp) == -1)
         {//读PHYCFGR寄存器bit0,若为1,则表示网络已经连接
                printf("Unknown PHY Link stauts.\r\n");
         }
    }while(tmp == PHY_LINK_OFF);

    W5500_Load_Net_Parameters();//装载W5500的本地网络参数和端口0的网络参数
    TIM2_Interrupt_Initializtion(1000,72);//当arr=1000,psc=72时,则为1ms,误差为1us;
    DHCP_Initialization();
//    network_init();//设置本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP
//    SOCKET1_Work();//端口1把域名"www.baidu.com"解析为IP地址
}

//函数功能:W5500端口0工作,用作输出调试数据
void SOCKET0_Work(void)
{
    uint16_t len=0;

    switch(getSn_SR(SOCK_TCPS))//获取W5500端口0的状态寄存器
    {
        case SOCK_INIT://W5500端口0已经初始化
            connect(SOCK_TCPS,DstIP_Port0,DstPort_Port0);
          //将W5500端口0连接到远程IP地址DstIP_Port0和远程端口DstPort_Port0上
          break;

        case SOCK_ESTABLISHED://W5500端口0已经连接成功
            if(getSn_IR(SOCK_TCPS) & Sn_IR_CON)
            {//读端口0的Sn_IR中断标志寄存器的bit0
                setSn_IR(SOCK_TCPS, Sn_IR_CON);//回写清除中断标志
            }

            len=getSn_RX_RSR(SOCK_TCPS);
            //读端口0接收缓冲区的数据长度
            if(len)
            {
                recv(SOCK_TCPS,gDATABUF,len);//读"W5500端口0"的数据,长度为len个字节,保存到gDATABUF
                printf("%s\r\n",gDATABUF);
                send(SOCK_TCPS,gDATABUF,len);//将gDATABUF的前len个字节通过"W5500端口0"发送出去
            }
            SOCKET0_Send_Local_Net_Parameters();//发送通过DHCP获取到的本地IP地址
            SOCKET0_Send_Domain_IP();//发送域名解析到的IP地址
            break;

        case SOCK_CLOSE_WAIT://W5500端口0处于等待关闭状态
            disconnect(SOCK_TCPS);//关闭端口0的连接
          break;

        case SOCK_CLOSED://W5500端口0处于关闭状态
            socket(SOCK_TCPS,Sn_MR_TCP,LocalPort0,0x00);//打开Socket0,打开一个本地端口
          break;
    }
}

/*
纯净 无劫持 无需再忍受被强扭去看广告或粗俗网站之痛苦
服务ip为:114.114.114.114 和 114.114.115.115

拦截 钓鱼病毒木马网站 增强网银、证券、购物、游戏、隐私信息安全
服务ip为:114.114.114.119 和 114.114.115.119

学校或家长可选拦截 色情网站 保护少年儿童免受网络色情内容的毒害
服务ip为:114.114.114.110 和 114.114.115.110
*/
//函数功能:端口1把域名"www.baidu.com"解析为IP地址
//DNS功能:DNS就是把域名解析为IP地址
void SOCKET1_Work(void)
{
    int32_t ret = 0;

//www.baidu.com的IP为"36.152.44.132"或" 36.152.44.93"
    strcpy((char*)domain_name,"www.baidu.com");//准备域名

//准备DNS服务器IP地址
  gWIZNETINFO.dns[0]=114;
    gWIZNETINFO.dns[1]=114;
    gWIZNETINFO.dns[2]=114;
    gWIZNETINFO.dns[3]=114;

    /* DNS client initialization */
    DNS_init(SOCK_DNS, gDATABUF);
    //端口1将gDATABUF用作DNS信息缓冲区
    Timer_Start();
    /* DNS procssing */
    if ((ret = DNS_run(gWIZNETINFO.dns, domain_name, domain_ip)) > 0)
    {
        // try to 1st DNS
        printf("> 1st DNS Reponsed\r\n");
    }
    else if(ret == -1)
    {
        printf("> MAX_DOMAIN_NAME is too small. Should be redefined it.\r\n");
        Timer_Stop();
        while(1);
    }
    else
    {
        printf("> DNS Failed\r\n");
        Timer_Stop();
        while(1);
    }

    if(ret > 0)//DNS解析成功
    {
        DNS_get_ip_flag=1;
        printf("> Translated %s to %d.%d.%d.%d\r\n",domain_name,domain_ip[0],domain_ip[1],domain_ip[2],domain_ip[3]);
    }
    Timer_Stop();
}

//函数功能:发送域名解析到的IP地址
void SOCKET0_Send_Domain_IP(void)
{
    char buf[20];
    uint16_t len=0;

    memset(gDATABUF,'\0',sizeof(gDATABUF));
    strcpy(buf,"DNS Result:\r\n");strcat((char*)gDATABUF,buf);

    strcat((char*)gDATABUF,(char*)domain_name);
    strcpy(buf,": ");strcat((char*)gDATABUF,buf);
    sprintf(buf,"%u.",domain_ip[0]);strcat((char*)gDATABUF,buf);
    sprintf(buf,"%u.",domain_ip[1]);strcat((char*)gDATABUF,buf);
    sprintf(buf,"%u.",domain_ip[2]);strcat((char*)gDATABUF,buf);
    sprintf(buf,"%u",domain_ip[3]);strcat((char*)gDATABUF,buf);
    strcpy(buf,"\r\n");strcat((char*)gDATABUF,buf);
    len=strlen( (char*)gDATABUF );
    send(SOCK_TCPS,gDATABUF,len);//发送数据
}

/*
MAC: 00 08 DC 11 11 11 
Local IP: 192.168.1.241
LocalGateway: 192.168.1.1
LocalSubnetMask: 255.255.255.0
*/
//函数功能:发送通过DHCP获取到的本地IP地址
void SOCKET0_Send_Local_Net_Parameters(void)
{
    char buf[20];
    uint16_t len=0;

    memset(gDATABUF,'\0',sizeof(gDATABUF));
    strcpy(buf,"DHCP Result:\r\n");strcat((char*)gDATABUF,buf);

    strcpy(buf,"MAC: ");strcat((char*)gDATABUF,buf);
    sprintf(buf,"%02X ",gWIZNETINFO.mac[0]);strcat((char*)gDATABUF,buf);
    sprintf(buf,"%02X ",gWIZNETINFO.mac[1]);strcat((char*)gDATABUF,buf);
    sprintf(buf,"%02X ",gWIZNETINFO.mac[2]);strcat((char*)gDATABUF,buf);
    sprintf(buf,"%02X ",gWIZNETINFO.mac[3]);strcat((char*)gDATABUF,buf);
    sprintf(buf,"%02X ",gWIZNETINFO.mac[4]);strcat((char*)gDATABUF,buf);
    sprintf(buf,"%02X ",gWIZNETINFO.mac[5]);strcat((char*)gDATABUF,buf);
    strcpy(buf,"\r\n");strcat((char*)gDATABUF,buf);
    len=strlen( (char*)gDATABUF );

    strcpy(buf,"Local IP: ");strcat((char*)gDATABUF,buf);
    sprintf(buf,"%u.",gWIZNETINFO.ip[0]);strcat((char*)gDATABUF,buf);
    sprintf(buf,"%u.",gWIZNETINFO.ip[1]);strcat((char*)gDATABUF,buf);
    sprintf(buf,"%u.",gWIZNETINFO.ip[2]);strcat((char*)gDATABUF,buf);
    sprintf(buf,"%u",gWIZNETINFO.ip[3]);strcat((char*)gDATABUF,buf);
    strcpy(buf,"\r\n");strcat((char*)gDATABUF,buf);

    strcpy(buf,"LocalGateway: ");strcat((char*)gDATABUF,buf);
    sprintf(buf,"%u.",gWIZNETINFO.gw[0]);strcat((char*)gDATABUF,buf);
    sprintf(buf,"%u.",gWIZNETINFO.gw[1]);strcat((char*)gDATABUF,buf);
    sprintf(buf,"%u.",gWIZNETINFO.gw[2]);strcat((char*)gDATABUF,buf);
    sprintf(buf,"%u",gWIZNETINFO.gw[3]);strcat((char*)gDATABUF,buf);
    strcpy(buf,"\r\n");strcat((char*)gDATABUF,buf);

    strcpy(buf,"LocalSubnetMask: ");strcat((char*)gDATABUF,buf);
    sprintf(buf,"%u.",gWIZNETINFO.sn[0]);strcat((char*)gDATABUF,buf);
    sprintf(buf,"%u.",gWIZNETINFO.sn[1]);strcat((char*)gDATABUF,buf);
    sprintf(buf,"%u.",gWIZNETINFO.sn[2]);strcat((char*)gDATABUF,buf);
    sprintf(buf,"%u",gWIZNETINFO.sn[3]);strcat((char*)gDATABUF,buf);
    strcpy(buf,"\r\n");strcat((char*)gDATABUF,buf);
    len=strlen( (char*)gDATABUF );
    send(SOCK_TCPS,gDATABUF,len);//发送数据
}

//请求IP地址函数
void dhcp_assign(void)
{
    uint8_t tmpstr[6];

    getIPfromDHCP(gWIZNETINFO.ip);//读本地IP地址
    getGWfromDHCP(gWIZNETINFO.gw);
    getSNfromDHCP(gWIZNETINFO.sn);
    getDNSfromDHCP(gWIZNETINFO.dns);

    gWIZNETINFO.dhcp = NETINFO_DHCP;

    ctlnetwork(CN_SET_NETINFO, (void*)&gWIZNETINFO);
    //设置本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP
    //设置MAC地址,将gWIZNETINFO.mac写入W5500;
    //设置网关,将gWIZNETINFO.gw写入W5500;
    //设置子网掩码,将gWIZNETINFO.sn写入W5500
    //设置本地IP地址,将gWIZNETINFO.ip写入W5500
    //将gWIZNETINFO.dns[]拷贝到_DNS_[]中
    //将gWIZNETINFO.dhcp保存到_DHCP_中

    ctlnetwork(CN_GET_NETINFO, (void*)&gWIZNETINFO);
    //读本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP
    //读MAC地址,保存到gWIZNETINFO.mac
    //读网关,保存到gWIZNETINFO.gw
    //读子网掩码,保存到gWIZNETINFO.sn
    //读本地IP地址,保存到gWIZNETINFO.ip
    //将_DNS_[]拷贝到gWIZNETINFO.dns[]中
    //将_DHCP_保存到gWIZNETINFO.dhcp中

    ctlwizchip(CW_GET_ID,(void*)tmpstr);
    //读W5500的ID,保存到tmpstr[6]中,"W5500\0",这是ioLibrary驱动定义的ID;
    //在wizchip_conf.h中定义_WIZCHIP_ID_为"W5500\0"

    printf("\r\n=== %s NET CONF ===\r\n",(char*)tmpstr);
    //串口输出W5500的ID

    printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n",gWIZNETINFO.mac[0],gWIZNETINFO.mac[1],gWIZNETINFO.mac[2],
    gWIZNETINFO.mac[3],gWIZNETINFO.mac[4],gWIZNETINFO.mac[5]);//串口输出W5500的MAC地址

    printf("SIP: %d.%d.%d.%d\r\n", gWIZNETINFO.ip[0],gWIZNETINFO.ip[1],gWIZNETINFO.ip[2],gWIZNETINFO.ip[3]);
    //串口输出W5500的IP地址

    printf("GAR: %d.%d.%d.%d\r\n", gWIZNETINFO.gw[0],gWIZNETINFO.gw[1],gWIZNETINFO.gw[2],gWIZNETINFO.gw[3]);
    //串口输出W5500的网关地址

    printf("SUB: %d.%d.%d.%d\r\n", gWIZNETINFO.sn[0],gWIZNETINFO.sn[1],gWIZNETINFO.sn[2],gWIZNETINFO.sn[3]);
    //串口输出W5500的子网掩码

    printf("DNS: %d.%d.%d.%d\r\n", gWIZNETINFO.dns[0],gWIZNETINFO.dns[1],gWIZNETINFO.dns[2],gWIZNETINFO.dns[3]);
    //串口输出W5500的DNS服务器IP地址
    printf("======================\r\n");
    printf("DHCP LEASED TIME:%u Sec.\r\n",getDHCPLeasetime());
}

void dhcp_update(void)
{
    dhcp_assign();
}
 
//IP地址冲突函数
void dhcp_conflict(void)
{
    printf("CONFLICT IP from DHCP\r\n");
    while(1);
}

//DHCP初始化函数
void DHCP_Initialization(void)
{
    setSHAR(gWIZNETINFO.mac);//寄存器设置mac地址
    printf(" DHCP client running \r\n");
    DHCP_init(SOCKET_DHCP,gDATABUF);//使用端口2初始化DHCP
    reg_dhcp_cbfunc(dhcp_assign, dhcp_update, dhcp_conflict);
    dhcp_retry = 0;
}

//函数功能;W5500端口2工作:使用端口2获取动态IP地址
void SOCKET2_Work(void)
{
    uint8_t retval = 0;

    if (gWIZNETINFO.dhcp == NETINFO_DHCP)
    {
        retval = DHCP_run();
        if (retval == DHCP_IP_LEASED)
        {
            if (dhcp_get_ip_flag == 0)
            {
                printf("DHCP success\r\n");
                dhcp_get_ip_flag = 1;//本地获取到IP地址
            }
        }
        else if (retval == DHCP_FAILED)
        {
            dhcp_get_ip_flag = 0;
            dhcp_retry++;
            if (dhcp_retry <= DHCP_RETRY_COUNT)
            {
                printf(" DHCP timeout occurred and retry %d \r\n", dhcp_retry);
            }
        }

        if (dhcp_retry > DHCP_RETRY_COUNT)
        {
            printf(" DHCP failed \r\n");
            DHCP_stop();
            while (1);
        }
    }

    if(dhcp_get_ip_flag)//本地获取到IP地址
    {
        if(DNS_get_ip_flag==0)
        {
        network_init();//设置本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP
        SOCKET1_Work();//端口1把域名"www.baidu.com"解析为IP地址
        }
        SOCKET0_Work();//W5500端口0工作,用作输出调试数据
    }
}

2、W5500_HD_Driver.h头文件

#ifndef	_W5500_HD_Driver_H_
#define	_W5500_HD_Driver_H_#include "stm32f10x.h"//使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,int16_t,int32_t,int64_t
#include "wizchip_conf.h"extern wiz_NetInfo gWIZNETINFO;//W5500的网络参数#define SOCK_TCPS   0  //端口0用来连接网络调试助手
#define SOCK_DNS    1  //端口1用作域名解析
#define SOCKET_DHCP 2  //端口2用作DHCPextern uint16_t LocalPort0;	   //端口0的端口号
extern uint8_t DstIP_Port0[4]; //端口0的远程IP地址
extern uint16_t	DstPort_Port0; //端口0的远程端口号#define DATA_BUF_SIZE   2048
extern uint8_t gDATABUF[DATA_BUF_SIZE];#define	W5500_CS_high()   GPIO_SetBits(GPIOA,GPIO_Pin_4)   //W5500片选引脚
#define	W5500_CS_low()    GPIO_ResetBits(GPIOA,GPIO_Pin_4) //W5500片选引脚extern void W5500_Initialization(void);
extern void SOCKET0_Work(void);
extern void SOCKET2_Work(void);
#endif

3、Timer2.c

#include "Timer2.h"
#include "dns.h"
#include "dhcp.h"uint16_t TIM2_CNT;void TIM2_Interrupt_Initializtion(u16 arr,u16 psc);//APB1时钟为36MHz
//arr:自动重装值。
//psc:时钟预分频数
//TIM_CKD_DIV1:定时器时钟 = 输入频率
//TIM_CKD_DIV2:定时器时钟 = 输入频率/2
//TIM_CKD_DIV4:定时器时钟 = 输入频率/4
//TIM2_Interrupt_Initializtion(1000,72);//当arr=1000,psc=72时,则为1ms,误差为1us;
void TIM2_Interrupt_Initializtion(u16 arr,u16 psc)
{TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;//声明一个TIM_TimeBaseInitTypeDef类型的结构变量TIM_TimeBaseStructureNVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //使能定时器TIM2的APB1外设时钟TIM_TimeBaseStructure.TIM_Period=(arr-1);//自动重装载寄存器周期的值(计数值)TIM_TimeBaseStructure.TIM_Prescaler=(psc-1);//设置用来作为TIMx时钟频率除数的预分频值TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;//设置时钟分割:TDTS = Tck_tim//计算公式:arr*psc/72000000/1,当arr=1000,psc=36时,则为1ms,误差为1us;TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;//TIM向上计数模式 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);//根据指定的参数初始化TIMx的时间基数单位TIM_SetCounter(TIM2,0);                      //设置TIM2的计数器值为0;TIM_ClearFlag(TIM2, TIM_FLAG_Update);        //清除TIM2溢出的待处理标志位TIM_ClearITPendingBit(TIM2, TIM_IT_Update ); //清除TIM2中断的待处理位TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE ); //允许TIM2溢出产生中断//中断优先级NVIC设置//NVIC_PriorityGroup_4设置NVIC中断分组4:表示抢占优先级为4位,取值为0~15,没有响应优先级,取值为0//NVIC_PriorityGroup_3设置NVIC中断分组3:表示抢占优先级为3位,取值为0~7,响应优先级只有1位,取值为0~1//NVIC_PriorityGroup_2设置NVIC中断分组3:表示抢占优先级为2位,取值为0~3,响应优先级只有2位,取值为0~3//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;  //TIM2中断NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //设置抢占优先级为0NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  //设置响应优先级为0NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;     //IRQ通道被使能NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化NVIC嵌套向量中断控制寄存器TIM_Cmd(TIM2, ENABLE);//使能TIM2模块RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,DISABLE);//先关闭TIM2时钟,等待使用    
}//函数功能:TIM2每1ms中断一次
void TIM2_IRQHandler(void)
{if ( TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET ) {TIM2_CNT++;if(TIM2_CNT>1000){TIM2_CNT=0;DNS_time_handler();  //DNS里面有一个超时机制DHCP_time_handler(); //DHCP里面有一个超时机制}TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update);  		 }		 	
}

5、Timer2.h

#ifndef _Timer2_H
#define _Timer2_H#include "stm32f10x.h"//使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,int16_t,int32_t,int64_t#define Timer_Start()  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //使能定时器TIM2的APB1外设时钟
#define Timer_Stop()   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,DISABLE); //不使能定时器TIM2的APB1外设时钟
extern void TIM2_Interrupt_Initializtion(u16 arr,u16 psc);#endif

6、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 "W5500_HD_Driver.h"//#include "W5500_Variable.h"const char CPU_Reset_REG[]="\r\nCPU reset!\r\n";
int main(void)
{//	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"W5500_Initialization();//1.初始化SPI接口//2.注册相关函数//3.设置W5500每个端口的发送缓冲区和接收缓冲区的大小均为2K字节//4.等待"以太网"连接完成//5.装载本地网络参数//6.设置本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCPLED_Init();LED0_ON();while(1){LED0=!LED0;delay_ms(1000);SOCKET2_Work();//W5500端口2工作:使用端口2获取动态IP地址}
}

相关文章:

  • 生产者 - 消费者模式实现方法整理
  • python + streamlink 下载 vimeo 短视频
  • 【Element UI】表单及其验证规则详细
  • DAY 23 训练
  • Python 3.11详细安装步骤(包含安装包)Python 3.11详细图文安装教程
  • Python 基础之函数命名
  • Nginx应用场景详解与配置指南
  • 【时时三省】(C语言基础)字符数组应用举例2
  • DeepSeek-R1 Supervised finetuning and reinforcement learning (SFT + RL)
  • MATLAB安装常见问题及解决办法
  • 开源项目实战学习之YOLO11:12.4 ultralytics-models-sam-memory_attention.py源码分析
  • 强化学习中,frames(帧)和 episodes(回合)
  • 重排序模型解读 mxbai-rerank-base-v2 强大的重排序模型
  • 我司助力高校打造「智慧创新AI学习中心」
  • 互联网大厂Java求职面试:AI驱动的短视频直播平台架构设计
  • 软件设计师考试结构型设计模式考点全解析
  • 学习深度学习是否要先学习机器学习?
  • 非对称加密算法(公钥加密算法)
  • 常见位运算总结
  • 【Ubuntu】Waydroid-Linux安卓模拟器安装
  • 2024年全国博物馆接待观众14.9亿人次
  • 本周看啥|《歌手》今晚全开麦直播,谁能斩获第一名?
  • 网易有道一季度净利润同比增长247%:有能力在今年实现更强劲的利润增长
  • 湖北宜化拟斥资超32亿加价回购“弃子”,布局上游煤炭业务
  • 为何选择上海?两家外企提到营商环境、人才资源……
  • 《克莱默夫妇》导演罗伯特·本顿去世,终年92岁