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