作者共發了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狀態常量所在的頭文件 |