MINI-STM32 DHCP问题分析

2019-07-20 01:37发布

本帖最后由 guoqingli1123 于 2016-10-12 11:39 编辑

最近在调试MINI-STM32的DHCP。一开始调试的挺顺利,用家里的路由器很快就调试成功了。但后来在公司换了个路由器调试怎么都获取不了IP地址。电脑可以正常获取IP地址。很郁闷。网上也没有找到答案。不能DHCP的路由器是D-LINK,非常老的路由器,我又找了个路由器磊科的,比较新,试了一下很快获取了IP地址。很纳闷。为啥电脑用D-LINK,磊科的都可以,而STM32-MINI板不行。于是进行了抓包
如下所示
DLINK.png
以上为DLINK的。可以看到DLINK提供的offer包,BOOTP标志为0x0000, 单播
此时STM32-MINI板没有发出Request包,获取DHCP失败
而电脑并没有按照单播的要求进行回复,而是直接回复了广播包,一下就获取到了IP地址

然后对磊科的路由器进行抓包如下
leke.png
发现磊科路由器提供的offer包,bootp标志为0x8000, 组播
此时STM32-MINI板能够正确获取到IP地址。


我试了几个路由发现只要发出的是0x0000的都获取不到IP地址。0x8000的都能正确获取。猜测lwip不支持0x0000模式????
怎么修改还没有解决方案。原子哥。。。求助。。。。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
11条回答
guoqingli1123
2019-07-21 02:45
gzthss 发表于 2019-5-24 09:05
初始化哪里的问题 能说下嘛 遇到同样的问题ile

u8 version;
    u16 retry=0;
    u32 temp;

    GPIO_InitTypeDef GPIO_InitStructure;
    SPI_InitTypeDef  SPI_InitStructure;
    EXTI_InitTypeDef EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    memset((void *)&enc28j60_dev, 0, sizeof(dev_strucrt));
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO, ENABLE);         //使能PA,C端口时钟


    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_SetBits(GPIOA,GPIO_Pin_4);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;           
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    GPIO_SetBits(GPIOC,GPIO_Pin_4);


    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1);

    EXTI_InitStructure.EXTI_Line = EXTI_Line1;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);

    EXTI_ClearITPendingBit(EXTI_Line1);

    NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);


    SPI1_Init();
    SPI_Cmd(SPI1, DISABLE);

    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;       
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_Init(SPI1, &SPI_InitStructure);
    SPI_Cmd(SPI1, ENABLE);

    SPI1_SetSpeed(SPI_BaudRatePrescaler_8);

    temp=*(vu32*)(0x1FFFF7F0);
   
    if(sysSave->macSetEnable == 1)
    {
        memcpy(enc28j60_dev.macaddr, sysSave->mac, 6);
    }
    else
    {
        enc28j60_dev.macaddr[0]=MAC0;
        enc28j60_dev.macaddr[1]=MAC1;
        enc28j60_dev.macaddr[2]=MAC2;
        enc28j60_dev.macaddr[3]=(temp>>16)&0XFF;
        enc28j60_dev.macaddr[4]=(temp>>8)&0XFFF;
        enc28j60_dev.macaddr[5]=temp&0XFF;      
    }

    if(enc28j60_dev.macaddr[0] != MAC0)
        enc28j60_dev.macaddr[0] = MAC0;
    if(enc28j60_dev.macaddr[1] != MAC1)
        enc28j60_dev.macaddr[1] = MAC1;
    if(enc28j60_dev.macaddr[2] != MAC2)
        enc28j60_dev.macaddr[2] = MAC2;
   
   
    ENC28J60_RST=0;
    G_TIME_DelayMs(10);         
    ENC28J60_RST=1;                            
    G_TIME_DelayMs(10);       
    ENC28J60_Write_Op(ENC28J60_SOFT_RESET,0,ENC28J60_SOFT_RESET);
    while(!(ENC28J60_Read(ESTAT)&ESTAT_CLKRDY)&&retry<250)
    {
        retry++;
        G_TIME_DelayMs(1);
    }       
    if(retry>=250)
        return 1;
    version=ENC28J60_Get_EREVID();
    printf("ENC28J60 Version=%d ", version);
    enc28j60_dev.NextPacketPtr=RXSTART_INIT;
    //接收缓冲器由一个硬件管理的循环FIFO 缓冲器构成。
    //寄存器对ERXSTH:ERXSTL 和ERXNDH:ERXNDL 作
    //为指针,定义缓冲器的容量和其在存储器中的位置。
    //ERXST和ERXND指向的字节均包含在FIFO缓冲器内。
    //当从以太网接口接收数据字节时,这些字节被顺序写入
    //接收缓冲器。 但是当写入由ERXND 指向的存储单元
    //后,硬件会自动将接收的下一字节写入由ERXST 指向
    //的存储单元。 因此接收硬件将不会写入FIFO 以外的单
    //元。
    //设置接收起始字节       
    ENC28J60_Write(ERXSTL,RXSTART_INIT&0XFF);        //设置接收缓冲区起始地址低8位
    ENC28J60_Write(ERXSTH,RXSTART_INIT>>8);                //设置接收缓冲区起始地址高8位
    //设置接收接收字节
    ENC28J60_Write(ERXNDL,RXSTOP_INIT&0XFF);       
    ENC28J60_Write(ERXNDH,RXSTOP_INIT>>8);
    //设置发送起始字节
    ENC28J60_Write(ETXSTL,TXSTART_INIT&0XFF);
    ENC28J60_Write(ETXSTH,TXSTART_INIT>>8);
    //设置发送结束字节
    ENC28J60_Write(ETXNDL,TXSTOP_INIT&0XFF);
    ENC28J60_Write(ETXNDH,TXSTOP_INIT>>8);
    //ERXWRPTH:ERXWRPTL 寄存器定义硬件向FIFO 中
    //的哪个位置写入其接收到的字节。 指针是只读的,在成
    //功接收到一个数据包后,硬件会自动更新指针。 指针可
    //用于判断FIFO 内剩余空间的大小  8K-1500。
    //设置接收读指针字节
    ENC28J60_Write(ERXRDPTL,RXSTART_INIT&0XFF);
    ENC28J60_Write(ERXRDPTH,RXSTART_INIT>>8);
    //接收过滤器
    //UCEN:单播过滤器使能位
    //当ANDOR = 1 时:
    /*  //1 = 目标地址与本地MAC 地址不匹配的数据包将被丢弃
    //0 = 禁止过滤器
    //当ANDOR = 0 时:
    //1 = 目标地址与本地MAC 地址匹配的数据包会被接受
    //0 = 禁止过滤器
    //CRCEN:后过滤器CRC 校验使能位
    //1 = 所有CRC 无效的数据包都将被丢弃
    //0 = 不考虑CRC 是否有效
    //PMEN:格式匹配过滤器使能位
    //当ANDOR = 1 时:
    //1 = 数据包必须符合格式匹配条件,否则将被丢弃
    //0 = 禁止过滤器
    //当ANDOR = 0 时:
    //1 = 符合格式匹配条件的数据包将被接受
    //0 = 禁止过滤器
    */
    ENC28J60_Write(ERXFCON,ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN|ERXFCON_BCEN);
    ENC28J60_Write(EPMM0,0X3F);
    ENC28J60_Write(EPMM1,0X30);
    ENC28J60_Write(EPMCSL,0Xf9);
    ENC28J60_Write(EPMCSH,0Xf7);
    /*
    //bit 0 MARXEN:MAC 接收使能位
    //1 = 允许MAC 接收数据包
    //0 = 禁止数据包接收
    //bit 3 TXPAUS:暂停控制帧发送使能位
    //1 = 允许MAC 发送暂停控制帧(用于全双工模式下的流量控制)
    //0 = 禁止暂停帧发送
    //bit 2 RXPAUS:暂停控制帧接收使能位
    //1 = 当接收到暂停控制帧时,禁止发送(正常操作)
    //0 = 忽略接收到的暂停控制帧
    */
    ENC28J60_Write(MACON1,MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
    //将MACON2 中的MARST 位清零,使MAC 退出复位状态。
    ENC28J60_Write(MACON2,0x00);
    /*
    //bit 7-5 PADCFG2ACDFG0:自动填充和CRC 配置位
    //111 = 用0 填充所有短帧至64 字节长,并追加一个有效的CRC
    //110 = 不自动填充短帧
    //101 = MAC 自动检测具有8100h 类型字段的VLAN 协议帧,并自动填充到64 字节长。如果不
    //是VLAN 帧,则填充至60 字节长。填充后还要追加一个有效的CRC
    //100 = 不自动填充短帧
    //011 = 用0 填充所有短帧至64 字节长,并追加一个有效的CRC
    //010 = 不自动填充短帧
    //001 = 用0 填充所有短帧至60 字节长,并追加一个有效的CRC
    //000 = 不自动填充短帧
    //bit 4 TXCRCEN:发送CRC 使能位
    //1 = 不管PADCFG如何,MAC都会在发送帧的末尾追加一个有效的CRC。 如果PADCFG规定要
    //追加有效的CRC,则必须将TXCRCEN 置1。
    //0 = MAC不会追加CRC。 检查最后4 个字节,如果不是有效的CRC 则报告给发送状态向量。
    //bit 0 FULDPX:MAC 全双工使能位
    //1 = MAC工作在全双工模式下。 PHCON1.PDPXMD 位必须置1。
    //0 = MAC工作在半双工模式下。 PHCON1.PDPXMD 位必须清零。*/
    ENC28J60_Write(MACON3,MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN|MACON3_FULDPX);
    // 最大帧长度 1518
    ENC28J60_Write(MAMXFLL,MAX_FRAMELEN&0XFF);
    ENC28J60_Write(MAMXFLH,MAX_FRAMELEN>>8);
    //配置背对背包间间隔寄存器MABBIPG。当使用
    //全双工模式时,大多数应用使用15h 编程该寄存
    //器,而使用半双工模式时则使用12h 进行编程。
    ENC28J60_Write(MABBIPG,0x15);
    //配置非背对背包间间隔寄存器的低字节
    //MAIPGL。 大多数应用使用12h 编程该寄存器。
    //如果使用半双工模式,应编程非背对背包间间隔
    //寄存器的高字节MAIPGH。 大多数应用使用0Ch
    //编程该寄存器。
    ENC28J60_Write(MAIPGL,0x12);
    ENC28J60_Write(MAIPGH,0x0C);
    //设置MAC地址
    ENC28J60_Write(MAADR5,enc28j60_dev.macaddr[0]);
    ENC28J60_Write(MAADR4,enc28j60_dev.macaddr[1]);
    ENC28J60_Write(MAADR3,enc28j60_dev.macaddr[2]);
    ENC28J60_Write(MAADR2,enc28j60_dev.macaddr[3]);
    ENC28J60_Write(MAADR1,enc28j60_dev.macaddr[4]);
    ENC28J60_Write(MAADR0,enc28j60_dev.macaddr[5]);
    //配置PHY为全双工  LEDB为拉电流
    ENC28J60_PHY_Write(PHCON1,PHCON1_PDPXMD);       
    /*
    //HDLDIS:PHY 半双工环回禁止位
    //当PHCON1.PDPXMD = 1 或PHCON1.PLOOPBK = 1 时:
    //此位可被忽略。
    //当PHCON1.PDPXMD = 0 且PHCON1.PLOOPBK = 0 时:
    //1 = 要发送的数据仅通过双绞线接口发出
    //0 = 要发送的数据会环回到MAC 并通过双绞线接口发出*/
    ENC28J60_PHY_Write(PHCON2,PHCON2_HDLDIS);
    //ECON1 寄存器
    //寄存器3-1 所示为ECON1 寄存器,它用于控制
    //ENC28J60 的主要功能。 ECON1 中包含接收使能、发
    //送请求、DMA 控制和存储区选择位。          
    ENC28J60_Set_Bank(ECON1);
    /*
    //EIE: 以太网中断允许寄存器
    //bit 7 INTIE: 全局INT 中断允许位
    //1 = 允许中断事件驱动INT 引脚
    //0 = 禁止所有INT 引脚的活动(引脚始终被驱动为高电平)
    //bit 6 PKTIE: 接收数据包待处理中断允许位
    //1 = 允许接收数据包待处理中断
    //0 = 禁止接收数据包待处理中断*/
    ENC28J60_Write_Op(ENC28J60_BIT_FIELD_SET,EIE,EIE_INTIE|EIE_PKTIE|EIE_TXIE|EIE_TXERIE|EIE_RXERIE);
    /*
    // enable packet reception
    //bit 2 RXEN:接收使能位
    //1 = 通过当前过滤器的数据包将被写入接收缓冲器
    //0 = 忽略所有接收的数据包*/
    ENC28J60_Write_Op(ENC28J60_BIT_FIELD_SET,ECON1,ECON1_RXEN);

一周热门 更多>