基于W5500芯片实现DHCP自动获取IP功能
一、硬件连接
1. 电路连接
W5500引脚 | STM32引脚 | 功能说明 |
---|---|---|
SCLK | PA5 | SPI时钟 |
MOSI | PA7 | 主出从入 |
MISO | PA6 | 主入从出 |
CS | PA4 | 片选信号 |
INT | PA3 | 中断引脚 |
RESET | PA2 | 复位引脚 |
3.3V | 3.3V | 电源 |
GND | GND | 地线 |
2. 网络拓扑
[STM32] --SPI--> [W5500] --RJ45--> 局域网交换机↑DHCP服务器
二、软件实现步骤
1. 寄存器初始化
// W5500复位配置
void W5500_Reset() {GPIO_ResetBits(GPIOA, GPIO_Pin_2); // 拉低RESET引脚Delay_ms(100);GPIO_SetBits(GPIOA, GPIO_Pin_2); // 释放RESETDelay_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状态机实现
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);// 配置网络模式为DHCPsetNETINFO(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报文处理
// 构造DHCP Discover报文
void send_DHCP_Discover() {uint8_t dhcp_pkt[576] = {0};dhcp_pkt[0] = 1; // OP: BOOTREQUESTdhcp_pkt[1] = 1; // HTYPE: ETHERNETdhcp_pkt[2] = 6; // HLEN: 6字节MACdhcp_pkt[3] = 0; // HOPS: 0// 填充事务IDmemcpy(&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_DISCOVERsend_udp_packet(DHCP_SERVER_PORT, dhcp_pkt, 576);
}// 解析DHCP Offer报文
void parse_dhcp_offer(uint8_t *pkt) {// 提取服务器IPserver_ip[0] = pkt[16];server_ip[1] = pkt[17];server_ip[2] = pkt[18];server_ip[3] = pkt[19];// 提取分配IPassigned_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];
}
三、配置参数
1. DHCP超时设置
#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. 网络参数保存
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); // yiaddrmemcpy(subnet_mask, &ack_pkt[16+2+1], 4); // subnet_maskmemcpy(gateway_ip, &ack_pkt[16+2+2], 4); // routers
}
四、调试与验证
1. 逻辑分析仪抓包示例
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. 常见问题排查
现象 | 解决方案 |
---|---|
无DHCP响应 | 检查MAC地址唯一性,确认网络连通性 |
IP地址冲突 | 重启设备或联系网络管理员 |
租约时间异常 | 检查DHCP服务器配置 |
五、扩展功能实现
1. 静态IP切换
void set_static_ip() {setNETINFO(NETINFO_STATIC);setIPADDR(192,168,1,100); // 设置静态IPsetGATEWAY(192,168,1,1); // 设置网关setSUBNET(255,255,255,0); // 设置子网掩码
}
2. 多网卡支持
// 配置多个W5500芯片
void multi_w5500_init() {for(int i=0; i<MAX_W5500_NUM; i++) {W5500_Reset(i); // 复位不同片选setSHAR(mac_addr[i]); // 设置不同MACsetNETINFO(NETINFO_DHCP);// 启动DHCP}
}
六、性能优化
-
DMA传输:启用SPI DMA模式提升吞吐量
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);
-
低功耗模式:
// 进入睡眠模式前关闭网络 WIZCHIP_CS_HIGH(); HAL_GPIO_WritePin(GPIOA, GPIO_Pin_4, GPIO_PIN_SET); HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
参考代码 W5500 实现DHCP自动获取IP功能 www.youwenfan.com/contentcsj/71379.html
七、完整代码结构
├── Drivers/
│ ├── W5500/
│ │ ├── w5500.c # 底层驱动
│ │ └── w5500.h # 寄存器定义
│ └── STM32/
│ ├── spi.c # SPI接口实现
│ └── tim.c # 定时器配置
├── Middlewares/
│ └── DHCP_Client/ # DHCP协议栈
│ ├── dhcp.c
│ └── dhcp.h
└── Applications/└── main.c # 主程序入口