目前共有10篇帖子。
![]() |
原始程序:
https://zh.arslanbar.net/post.php?t=24571 打开lwipopts.h,把#define LWIP_DHCP 0改成#define LWIP_DHCP 1,启用DHCP。 然后修改main.c文件: #include <stdio.h> #include <stm32f10x.h> #include "lwip/etharp.h" // etharp_tmr函数所在的头文件 #include "lwip/init.h" // lwip_init函数所在的头文件 // 与DHCP有关的头文件 #include "lwip/dhcp.h" #include "lwip/prot/dhcp.h" // DHCP状态常量所在的头文件 #include "lwip/priv/tcp_priv.h" // tcp_tmr函数所在的头文件 #include "netif/ethernet.h" // ethernet_input函数所在头文件 #include "ENC28J60.h" // 这两个函数位于ethernetif.c中, 但没有头文件声明 err_t ethernetif_init(struct netif *netif); void ethernetif_input(struct netif *netif); // 声明httptest.c中的函数 void init_http(void); // printf串口输出 // 必须要在项目属性里勾选Use MicroLIB后才能使用 int fputc(int ch, FILE *fp) { if (fp == &__stdout) { if (ch == '\n') { // 遇到\n自动在前面添加\r USART1->DR = '\r'; while ((USART1->SR & USART_SR_TXE) == 0); } USART1->DR = ch; while ((USART1->SR & USART_SR_TXE) == 0); } return ch; } void show_addr(struct netif *netif) { // 获取网卡的DHCP信息 //struct dhcp *dhcp = netif->client_data[LWIP_NETIF_CLIENT_DATA_INDEX_DHCP]; struct dhcp *dhcp = netif_dhcp_data(netif); // 这个宏相当于上面的语句 // 显示IP地址 static uint8_t displayed = 0; if (dhcp->state == DHCP_STATE_BOUND) { // 如果DHCP分配成功就显示IP地址 if (displayed == 0) // 只显示一次 { printf("DHCP分配成功!\n"); printf("IP地址: %s\n", ip4addr_ntoa(&dhcp->offered_ip_addr)); printf("子网掩码: %s\n", ip4addr_ntoa(&dhcp->offered_sn_mask)); printf("网关: %s\n", ip4addr_ntoa(&dhcp->offered_gw_addr)); //printf("DHCP状态码: %d\n", dhcp->state); displayed = 1; } } else displayed = 0; } int main(void) { struct ip4_addr ipaddr, netmask, gw; struct netif enc28j60; uint8_t cnt = 0; // 配置PA口 RCC->APB2ENR = RCC_APB2ENR_IOPAEN; GPIOA->CRH = 0x000004b3; // PA8为开发板上的一个LED灯 GPIOA->CRL = 0xb4bb0080; GPIOA->BSRR = GPIO_BSRR_BS1; // PA1为网卡中断输出 // 配置SPI RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_BR_1; // 主机模式, 时钟至少需要8分频(BR=010), 也就是72MHz/8=9MHz SPI1->CR2 = SPI_CR2_SSOE; // 开CS片选输出 // 配置串口 RCC->APB2ENR |= RCC_APB2ENR_USART1EN; USART1->BRR = 0x271; // 波特率: 115200 USART1->CR1 = USART_CR1_UE | USART_CR1_TE; // 配置定时器 RCC->APB1ENR = RCC_APB1ENR_TIM6EN; TIM6->ARR = 2499; // 共2500个数, 2500*0.1ms=250ms TIM6->PSC = 7199; // 72MHz/7200=10kHz -> 0.1ms TIM6->CR1 = TIM_CR1_URS; // 防止UG=1时UIF置位 TIM6->EGR = TIM_EGR_UG; // 应用上述设置 TIM6->CR1 |= TIM_CR1_CEN; // 开定时器 lwip_init(); ip4_addr_set_zero(&ipaddr); // 暂时将IP地址设为0 ip4_addr_set_zero(&netmask); // 子网掩码设为0 ip4_addr_set_zero(&gw); // 网关也要设为0 netif_add(&enc28j60, &ipaddr, &netmask, &gw, NULL, ethernetif_init, ethernet_input); netif_set_default(&enc28j60); // 设为默认网卡 netif_set_up(&enc28j60); dhcp_start(&enc28j60); // 启动DHCP init_http(); // 初始化HTTP服务 while (1) { if (ENC28J60_GetPacketNum() != 0) { GPIOA->ODR ^= GPIO_ODR_ODR8; // PA8上的LED灯闪烁表明系统正常工作 ethernetif_input(&enc28j60); } show_addr(&enc28j60); // 如果DHCP分配地址成功就显示IP地址 // 若定时器溢出 if (TIM6->SR & TIM_SR_UIF) { // 250ms TIM6->SR &= ~TIM_SR_UIF; // 清除溢出标志 cnt++; if (cnt >= 250) { cnt = 0; // 250ms*240=1min dhcp_coarse_tmr(); } tcp_tmr(); // TCP定时处理 if (cnt % 2 == 0) dhcp_fine_tmr(); // 250ms*2=500ms if (cnt % 4 == 0) { // 250ms*4=1s etharp_tmr(); // ARP定时处理 } if (cnt % 20 == 0) GPIOA->ODR ^= GPIO_ODR_ODR8; // LED灯状态切换(250ms*20=5s) } } } |
![]() |
路由器中可以查看到DHCP分配的IP地址:
![]() |
![]() |
用分配的IP地址访问HTTP网站: |
![]() |
串口输出的内容:
![]() |
![]() |
【注意】
[1] lwipopts.h中不需要开ARP,也就是说不需要将LWIP_ARP定义为1 [2] 网卡驱动文件无需修改。不需要将ERXFCON_BCEN位设为1。 |
![]() |
手机连接无线路由器后,用浏览器通过自动分配的IP地址访问HTTP网站的截图: |
![]() |
回復5樓 @巨大八爪鱼 的內容:【注意】
[1] lwipopts.h中不需要开ARP,也就是说不需要将LWIP_ARP定义为1 [2] 网卡驱动文件无需修改。不需要将ERXFCON_BCEN位设为1。 虽然没有在lwipopts.h中开ARP,但在opts.h头文件中有这样的定义: 所以其实ARP是自动打开了的。 |
![]() |
【配置说明】 ip4_addr_set_zero(&netmask); |
![]() |
【设备名的配置】
现在,在路由器的DHCP设备列表页面显示的客户端名称是Unknown。为了让路由器能知道MAC地址对应的设备名称,可先在lwipopts.h中添加如下的定义: #define LWIP_NETIF_HOSTNAME 1 然后在main.c的dhcp_start(&enc28j60)前面加上这样一句话: enc28j60.hostname = "ENC28J60_Device"; 编译并下载程序后,路由器的页面就可以看到新的设备名称了: ![]() |
![]() |
if (dhcp->state == DHCP_STATE_BOUND)
可以用下面的语句代替: if (dhcp_supplied_address(netif)) 修改后可以去掉包含如下头文件的语句: #include "lwip/prot/dhcp.h" // DHCP状态常量所在的头文件 |