---
title: "Implement DHCP automatic IP address acquisition function based on W5500 chip"
url: "https://maker.wiznet.io/ronpang/projects/implement-dhcp-automatic-ip-address-acquisition-function-based-on-w5500-chip/"
markdown_url: "https://maker.wiznet.io/ronpang/projects/implement-dhcp-automatic-ip-address-acquisition-function-based-on-w5500-chip/md"
type: "UCC: User Created Content"
author: "alloutlove"
author_url: "https://www.cnblogs.com/ll55522201/p/19187104"
editor: "WIZnet"
editor_url: "https://maker.wiznet.io/"
original_author: "alloutlove"
original_url: "https://www.cnblogs.com/ll55522201/p/19187104"
published: "2026-01-06"
language: "en"
likes: 0
views: 415
comments: 0
source: "WIZnet Makers (https://maker.wiznet.io/)"
---

# Implement DHCP automatic IP address acquisition function based on W5500 chip

> Implement DHCP automatic IP address acquisition function based on W5500 chip

Original author: alloutlove (source: https://www.cnblogs.com/ll55522201/p/19187104)

## Article

## [**Implement DHCP automatic IP address acquisition function based on W5500 chip**](https://www.cnblogs.com/ll55522201/p/19187104)

#### **I. Hardware**

##### **1. Circuit connection**

| **W5500 pin** | **STM32 pin** | **Function Description** |
| --- | --- | --- |
| SCLK | PA5 | SPI clock |
| MOSI | PA7 | The main one goes out, the secondary one comes in. |
| MISO | PA6 | The main enters, the secondary exits |
| CS | PA4 | Chip select signal |
| INT | PA3 | Interrupt pin |
| RESET | PA2 | Reset pin |
| 3.3V | 3.3V | power supply |
| GND | GND | ground wire |

##### **2. Network Topology**

```css
[STM32] --SPI--> [W5500] --RJ45--> 局域网交换机
                  ↑
              DHCP服务器
```

---

#### **II. Software Implementation Steps**

##### **1. Register initialization**

```c
// W5500复位配置
void W5500_Reset() {
    GPIO_ResetBits(GPIOA, GPIO_Pin_2);  // 拉低RESET引脚
    Delay_ms(100);
    GPIO_SetBits(GPIOA, GPIO_Pin_2);    // 释放RESET
    Delay_ms(200);
}

// SPI接口配置（STM32 HAL库）
SPI_HandleTypeDef hspi1;

void MX_SPI1_Init(void) {
    hspi1.Instance = SPI1;
    hspi1.Init.Mode = SPI_MODE_MASTER;
    hspi1.Init.Direction = SPI_DIRECTION_2LINES;
    hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
    hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
    hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
    hspi1.Init.NSS = SPI_NSS_SOFT;
    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
    HAL_SPI_Init(&hspi1);
}
```

##### **2. DHCP State Machine Implementation**

```c
typedef enum {
    DHCP_INIT,
    DHCP_DISCOVER,
    DHCP_OFFER,
    DHCP_REQUEST,
    DHCP_ACK,
    DHCP_TIMEOUT
} DHCP_State;

DHCP_State dhcp_state = DHCP_INIT;
uint8_t dhcp_mac[6] = {0x00, 0x08, 0xDC, 0x12, 0x34, 0x56}; // 默认MAC地址

void DHCP_Init() {
    // 设置MAC地址
    setSHAR(dhcp_mac);
    
    // 配置网络模式为DHCP
    setNETINFO(NETINFO_DHCP);
    
    // 初始化DHCP定时器
    HAL_TIM_Base_Start_IT(&htim3); // 100ms定时器
}

void DHCP_Process() {
    switch(dhcp_state) {
        case DHCP_INIT:
            send_DHCP_Discover();
            dhcp_state = DHCP_DISCOVER;
            break;
            
        case DHCP_DISCOVER:
            if(receive_DHCP_Offer()) {
                dhcp_state = DHCP_OFFER;
            }
            break;
            
        case DHCP_OFFER:
            send_DHCP_Request();
            dhcp_state = DHCP_REQUEST;
            break;
            
        case DHCP_REQUEST:
            if(receive_DHCP_ACK()) {
                dhcp_state = DHCP_ACK;
                save_network_params(); // 保存IP等参数
            }
            break;
            
        case DHCP_TIMEOUT:
            // 超时处理：重试或切换模式
            break;
    }
}
```

##### **3. DHCP Message Processing**

```c
// 构造DHCP Discover报文
void send_DHCP_Discover() {
    uint8_t dhcp_pkt[576] = {0};
    
    dhcp_pkt[0] = 1;    // OP: BOOTREQUEST
    dhcp_pkt[1] = 1;    // HTYPE: ETHERNET
    dhcp_pkt[2] = 6;    // HLEN: 6字节MAC
    dhcp_pkt[3] = 0;    // HOPS: 0
    
    // 填充事务ID
    memcpy(&dhcp_pkt[4], &xid, 4);
    
    // 设置客户端MAC地址
    memcpy(&dhcp_pkt[28], dhcp_mac, 6);
    
    // 设置选项字段
    dhcp_pkt[53] = 53;  // DHCP消息类型
    dhcp_pkt[54] = 1;   // 消息类型长度
    dhcp_pkt[55] = 1;   // DHCP_DISCOVER
    
    send_udp_packet(DHCP_SERVER_PORT, dhcp_pkt, 576);
}

// 解析DHCP Offer报文
void parse_dhcp_offer(uint8_t *pkt) {
    // 提取服务器IP
    server_ip[0] = pkt[16];
    server_ip[1] = pkt[17];
    server_ip[2] = pkt[18];
    server_ip[3] = pkt[19];
    
    // 提取分配IP
    assigned_ip[0] = pkt[16+2+16]; // yiaddr字段
    assigned_ip[1] = pkt[16+2+17];
    assigned_ip[2] = pkt[16+2+18];
    assigned_ip[3] = pkt[16+2+19];
}
```

---

#### **III. Configuration Parameters**

##### **1. DHCP timeout settings**

```c
#define DHCP_TIMEOUT_MS  10000  // 总超时时间
#define DHCP_RETRY_INTERVAL 2000 // 重试间隔

volatile uint32_t dhcp_timer = 0;

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    if(htim->Instance == TIM3) {
        dhcp_timer += 100;
        if(dhcp_timer >= DHCP_TIMEOUT_MS) {
            dhcp_state = DHCP_TIMEOUT;
            dhcp_timer = 0;
        }
    }
}
```

##### **2. Saving network parameters**

```c
uint8_t assigned_ip[4] = {0};
uint8_t subnet_mask[4] = {255,255,255,0};
uint8_t gateway_ip[4] = {192,168,1,1};

void save_network_params() {
    // 从DHCP ACK报文提取参数
    memcpy(assigned_ip, &ack_pkt[16+2+16], 4);  // yiaddr
    memcpy(subnet_mask, &ack_pkt[16+2+1], 4);   // subnet_mask
    memcpy(gateway_ip, &ack_pkt[16+2+2], 4);    // routers
}
```

---

#### **IV. Debugging and Verification**

##### **1. Packet capture example using a logic analyzer**

```c
Time    | 操作类型      | 关键字段
---------------------------------------
0.00s   | DHCP Discover | MAC:00:08:DC:12:34:56
0.52s   | DHCP Offer    | ServerIP:192.168.1.254
0.85s   | DHCP Request  | RequestIP:192.168.1.100
1.20s   | DHCP ACK      | LeaseTime:86400s
```

##### **2. Troubleshooting Common Problems**

| **Phenomenon** | **Solution** |
| --- | --- |
| No DHCP response | Check MAC address uniqueness to confirm network connectivity. |
| IP address conflict | Restart the device or contact your network administrator. |
| Lease duration abnormal | Check DHCP server configuration |

---

#### **V. Implementation of Extended Functions**

##### **1. Static IP Switching**

```c
void set_static_ip() {
    setNETINFO(NETINFO_STATIC);
    setIPADDR(192,168,1,100);    // 设置静态IP
    setGATEWAY(192,168,1,1);     // 设置网关
    setSUBNET(255,255,255,0);    // 设置子网掩码
}
```

##### **2. Supports multiple network cards**

```c
// 配置多个W5500芯片
void multi_w5500_init() {
    for(int i=0; i<MAX_W5500_NUM; i++) {
        W5500_Reset(i);          // 复位不同片选
        setSHAR(mac_addr[i]);    // 设置不同MAC
        setNETINFO(NETINFO_DHCP);// 启动DHCP
    }
}
```

---

#### **VI. Performance OptimizationDMA Transfer** : Enable SPI DMA mode to improve throughput

```c
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64; // 10MHz
hspi1.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE; // 保持IO状态
HAL_SPI_Init(&hspi1);
```

**Low power mode** :

```c
// 进入睡眠模式前关闭网络
WIZCHIP_CS_HIGH();
HAL_GPIO_WritePin(GPIOA, GPIO_Pin_4, GPIO_PIN_SET);
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
```

Refer to the W5500 code to implement DHCP automatic IP address acquisition function: www.youwenfan.com/contentcnk/71379.html

#### **VII. Complete Code Structure**

```plaintext
├── Drivers/
│   ├── W5500/
│   │   ├── w5500.c       # 底层驱动
│   │   └── w5500.h       # 寄存器定义
│   └── STM32/
│       ├── spi.c         # SPI接口实现
│       └── tim.c         # 定时器配置
├── Middlewares/
│   └── DHCP_Client/      # DHCP协议栈
│       ├── dhcp.c
│       └── dhcp.h
└── Applications/
    └── main.c            # 主程序入口
```

---

Source: https://maker.wiznet.io/ronpang/projects/implement-dhcp-automatic-ip-address-acquisition-function-based-on-w5500-chip/
