原始程序:
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)
}
}
}