作者共發了10篇帖子。 內容轉換:不轉換▼
 
點擊 回復
851 9
【程序】lwip-2.0.2通过DHCP自动从路由器获取IP地址
一派護法 十九級
1樓 發表于:2017-3-29 22:04
原始程序:
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)
        }
    }
}
一派護法 十九級
2樓 發表于:2017-3-29 22:08
路由器中可以查看到DHCP分配的IP地址:
一派護法 十九級
3樓 發表于:2017-3-29 22:09

用分配的IP地址访问HTTP网站:

一派護法 十九級
4樓 發表于:2017-3-29 22:10
串口输出的内容:

一派護法 十九級
5樓 發表于:2017-3-29 22:15
【注意】
[1] lwipopts.h中不需要开ARP,也就是说不需要将LWIP_ARP定义为1
[2] 网卡驱动文件无需修改。不需要将ERXFCON_BCEN位设为1。
一派護法 十九級
6樓 發表于:2017-3-29 22:18

手机连接无线路由器后,用浏览器通过自动分配的IP地址访问HTTP网站的截图:

一派護法 十九級
7樓 發表于:2017-3-30 10:07
回復5樓 @巨大八爪鱼 的內容:
【注意】
[1] lwipopts.h中不需要开ARP,也就是说不需要将LWIP_ARP定义为1
[2] 网卡驱动文件无需修改。不需要将ERXFCON_BCEN位设为1。...

虽然没有在lwipopts.h中开ARP,但在opts.h头文件中有这样的定义:
#if !defined LWIP_ARP || defined __DOXYGEN__
#define LWIP_ARP                        1
#endif
也就是说只要没有在lwipopts.h中定义LWIP_ARP,就会自动将LWIP_ARP定义为1。

所以其实ARP是自动打开了的。

一派護法 十九級
8樓 發表于:2017-3-31 16:09

【配置说明】
定时器设为250ms溢出一次,主循环while(1)中添加了一些与DHCP有关的响应函数。
请在ethernetif.c中设置一个合适的网卡MAC地址,以免路由器无法识别导致网卡只能接收不能发送数据:
/* set MAC hardware address */
netif->hwaddr[0] = 0;
netif->hwaddr[1] = 'R';
netif->hwaddr[2] = 'M';
netif->hwaddr[3] = 'N';
netif->hwaddr[4] = 'E';
netif->hwaddr[5] = 'T';


另外,由于现在IP地址是自动分配,所以初始IP地址、子网掩码和网关都为0,调用netif_add函数时可直接用IP_ADDR_ANY代替,不再单独设3个地址变量:
lwip_init();
netif_add(&enc28j60, IP_ADDR_ANY, IP_ADDR_ANY, IP_ADDR_ANY, NULL, ethernetif_init, ethernet_input);
netif_set_default(&enc28j60);
netif_set_up(&enc28j60);
之前声明的struct ip4_addr ipaddr, netmask, gw可以删除了。
以下三句话也要去掉:
ip4_addr_set_zero(&ipaddr);

ip4_addr_set_zero(&netmask);
ip4_addr_set_zero(&gw);

一派護法 十九級
9樓 發表于:2017-3-31 18:36
【设备名的配置】
现在,在路由器的DHCP设备列表页面显示的客户端名称是Unknown。为了让路由器能知道MAC地址对应的设备名称,可先在lwipopts.h中添加如下的定义:
#define LWIP_NETIF_HOSTNAME 1
然后在main.c的dhcp_start(&enc28j60)前面加上这样一句话:
enc28j60.hostname = "ENC28J60_Device";
编译并下载程序后,路由器的页面就可以看到新的设备名称了:


一派護法 十九級
10樓 發表于:2017-4-2 21:40
if (dhcp->state == DHCP_STATE_BOUND)
可以用下面的语句代替:
if (dhcp_supplied_address(netif))
修改后可以去掉包含如下头文件的语句:
#include "lwip/prot/dhcp.h" // DHCP状态常量所在的头文件

回復帖子

內容:
用戶名: 您目前是匿名發表
驗證碼:
(快捷鍵:Ctrl+Enter)
 

本帖信息

點擊數:851 回複數:9
評論數: ?
作者:巨大八爪鱼
最後回復:巨大八爪鱼
最後回復時間:2017-4-2 21:40
 
©2010-2024 Arslanbar Ver2.0
除非另有聲明,本站採用共享創意姓名標示-相同方式分享 3.0 Unported許可協議進行許可。