六、STM32F4+标准库+LWIP1.4.1移植+无操作系统

最快最简单的移植LWIP协议栈,可改可不改的东西统一不修改。后期学会了有能力了再回过头来修改,操作复杂理论复杂,同时讲解对新手不是很友好,故此此文档只讲操作无任何理论讲解。

零、所需文件及环境        

        1、第四章建立好的串口2当调试口程序   

        2、编译环境MDK5(KEIL5)   

        3、一个STM32F407VET6硬件

        4、一个下载器j-link 或 st-link等

        5.代码编辑器 Notepad++   (可以不要 用记事本也能编译  都是习惯的问题)

        6.USB转TTL设备  用于连接电脑串口助手

        7. LWIP1.4.1源码    lwIP - A Lightweight TCP/IP stack - Summary [Savannah]  

        8.ST以太网库https://www.st.com.cn/zh/embedded-software/stsw-stm32070.html#

0.1 LWIP1.4.1源码下载    高版本需要自己实验  稳定性来说降版本最好

0.2 ST以太网库下载  需要登录ST账号

0.3 解压三个文件

壹、复制第三章串口2当调试口程序

1.1 第0章为工程模版 但是真正应用时  灯、定时器、调试口 不管啥程序这仨都会用到 所以以后会把第三章程序当做我自己的基础工程。

1.2 复制第三章程序并修改名字

贰、添加及修改ST以太网库

2.1 添加以太网库 将STM32F4x7_ETH_LwIP_V1.1.1/Libraries文件夹下STM32F4x7_ETH_Driver文件夹复制到咱自己的Libraries文件夹下

2.2 进入STM32F4x7_ETH_Driver/inc文件夹,将stm32f4x7_eth_conf_template.h 重命名为stm32f4x7_eth_conf.h

2.3 将以太网库添加进工程文件并添加头文件路径

2.4 修改stm32f4x7_eth_conf.h

#ifndef __STM32F4x7_ETH_CONF_H
#define __STM32F4x7_ETH_CONF_H
#include "stm32f4xx.h"

#include "BSP_DELAY.h"

#define USE_ENHANCED_DMA_DESCRIPTORS

//如果使用自己定义的延时函数的话就注销掉下面一行代码,否则使用
//默认的低精度延时函数

#define USE_Delay         //使用默认延时函数,因此注销掉
#ifdef USE_Delay
//    #include "main.h"               
        #define _eth_delay_         BSP_DELAY_ms          //Delay为用户自己提供的高精度延时函数

#else
    #define _eth_delay_    ETH_Delay //默认的_eth_delay功能函数延时精度差
#endif

#ifdef         CUSTOM_DRIVER_BUFFERS_CONFIG
    //重新定义以太网接收和发送缓冲区的大小和数量
    #define ETH_RX_BUF_SIZE    ETH_MAX_PACKET_SIZE //接收缓冲区的大小
    #define ETH_TX_BUF_SIZE    ETH_MAX_PACKET_SIZE //发送缓冲区的大小
    #define ETH_RXBUFNB        20                  //接收缓冲区数量
    #define ETH_TXBUFNB        5                   //发送缓冲区数量
#endif
//*******************PHY配置块*******************
#ifdef USE_Delay
                #define PHY_RESET_DELAY            ((uint32_t)0x000000FF)         //PHY复位延时
                #define PHY_CONFIG_DELAY            ((uint32_t)0x00000FFF)                //PHY配置延时
                #define ETH_REG_WRITE_DELAY        ((uint32_t)0x00000001)                //向以太网寄存器写数据时的延时
#else
    #define PHY_RESET_DELAY    ((uint32_t)0x000FFFFF)    //PHY复位延时
    #define PHY_CONFIG_DELAY   ((uint32_t)0x00FFFFFF)    //PHY配置延时
    #define ETH_REG_WRITE_DELAY ((uint32_t)0x0000FFFF)    //向以太网寄存器写数据时的延时
#endif

//LAN8720 PHY芯片的状态寄存器
#define PHY_SR                                ((uint16_t)31)                         //LAN8720的PHY状态寄存器地址
#define PHY_SPEED_STATUS            ((uint16_t)0x0004)                //LAN8720 PHY速度值掩码
#define PHY_DUPLEX_STATUS            ((uint16_t)0x00010)                //LAN8720 PHY连接状态值掩码  
#endif
 

2.5 打开stm32f4x7_eth.c 屏蔽66-102行   这几个数组会BSP_LAN8720.c里面定义

2.6 编译一下 没有错误  如果有其他错误根据错误类型修改

叁、编写BSP_LAN8720.c与BSP_LAN8720.h代码

3.1复制BSP_LED文件夹,并重命名BSP_LAN8720

3. 打开BSP_LAN8720.c修改为

#include "BSP_LAN8720.h"
#include "stm32f4x7_eth.h"
#include "BSP_DELAY.h"

//#include "BSP_DEBUG.h"
    #include "BSP_LED.h"  


__align(4) ETH_DMADESCTypeDef DMARxDscrTab[ETH_RXBUFNB];    //以太网DMA接收描述符数据结构体指针  
__align(4) ETH_DMADESCTypeDef DMATxDscrTab[ETH_TXBUFNB];    //以太网DMA发送描述符数据结构体指针   
__align(4) uint8_t Rx_Buff[ETH_RX_BUF_SIZE*ETH_RXBUFNB];    //以太网底层驱动接收buffers指针   
__align(4) uint8_t Tx_Buff[ETH_TX_BUF_SIZE*ETH_TXBUFNB];    //以太网底层驱动发送buffers指针 

static void ETHERNET_NVICConfiguration(void);
//LAN8720初始化
//返回值:0,成功;
//    其他,失败
uint8_t LAN8720_Init(void)
{
    uint8_t rval=0;
    GPIO_InitTypeDef GPIO_InitStructure;
  
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOC, ENABLE);//使能GPIO时钟 RMII接口
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);   //使能SYSCFG时钟
  
    SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_RMII); //MAC和PHY之间使用RMII接口

    /*网络引脚设置 RMII接口
      ETH_MDIO -------------------------> PA2
      ETH_MDC --------------------------> PC1
      ETH_RMII_REF_CLK------------------> PA1
      ETH_RMII_CRS_DV ------------------> PA7
      ETH_RMII_RXD0 --------------------> PC4
      ETH_RMII_RXD1 --------------------> PC5
      ETH_RMII_TX_EN -------------------> PB11
      ETH_RMII_TXD0 --------------------> PB12
      ETH_RMII_TXD1 --------------------> PB13
      ETH_RESET-------------------------> PB14*/
                    
      //配置PA1 PA2 PA7
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;  
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_ETH); //引脚复用到网络接口上
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_ETH);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_ETH);

    //配置PC1,PC4 and PC5
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource1, GPIO_AF_ETH); //引脚复用到网络接口上
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource4, GPIO_AF_ETH);
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource5, GPIO_AF_ETH);
                                
    //配置PG11, PG14 and PG13 
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_ETH);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource12, GPIO_AF_ETH);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_ETH);
    
    //配置PD3为推完输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;    //推完输出
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;  
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    LAN8720_RST=0;                    //硬件复位LAN8720
    BSP_DELAY_ms(50);    
    LAN8720_RST=1;                     //复位结束 
    ETHERNET_NVICConfiguration();
    rval=ETH_MACDMA_Config();
    return !rval;                    //ETH的规则为:0,失败;1,成功;所以要取反一下 
}

//以太网中断分组配置
void ETHERNET_NVICConfiguration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    
    NVIC_InitStructure.NVIC_IRQChannel = ETH_IRQn;  //以太网中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0X00;  //中断寄存器组2最高优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0X01;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}


//得到8720的速度模式
//返回值:
//001:10M半双工
//101:10M全双工
//010:100M半双工
//110:100M全双工
//其他:错误.
uint8_t LAN8720_Get_Speed(void)
{
    uint8_t speed;
    speed=((ETH_ReadPHYRegister(0x00,31)&0x1C)>>2); //从LAN8720的31号寄存器中读取网络速度和双工模式
    return speed;
}

uint16_t LAN8720_Get_State(void)
{
    uint16_t State = 0;
    State =    ETH_ReadPHYRegister(0x00,1); //从LAN8720的31号寄存器中读取网络速度和双工模式
    return State;
}

uint16_t LAN8720_Get_State_TEXT(uint8_t REG)
{
    uint16_t State = 0;
    State =    ETH_ReadPHYRegister(0x00,REG); //从LAN8720的31号寄存器中读取网络速度和双工模式
    return State;
}
/
//以下部分为STM32F407网卡配置/接口函数.

//初始化ETH MAC层及DMA配置
//返回值:ETH_ERROR,发送失败(0)
//        ETH_SUCCESS,发送成功(1)
uint8_t ETH_MACDMA_Config(void)
{
    uint8_t rval;
    ETH_InitTypeDef ETH_InitStructure; 
    
    //使能以太网时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_ETH_MAC | RCC_AHB1Periph_ETH_MAC_Tx |RCC_AHB1Periph_ETH_MAC_Rx, ENABLE);
                        
    ETH_DeInit();                                  //AHB总线重启以太网
    ETH_SoftwareReset();                          //软件重启网络
    while (ETH_GetSoftwareResetStatus() == SET){;}//等待软件重启网络完成 
    
//    printf("ETH_MACDMA_Config ok\r\n");
    ETH_StructInit(&ETH_InitStructure);          //初始化网络为默认值  

    ///网络MAC参数设置 
    ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable;               //开启网络自适应功能
    ETH_InitStructure.ETH_LoopbackMode = ETH_LoopbackMode_Disable;                    //关闭反馈
    ETH_InitStructure.ETH_RetryTransmission = ETH_RetryTransmission_Disable;         //关闭重传功能
    ETH_InitStructure.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable;     //关闭自动去除PDA/CRC功能 
    ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Disable;                        //关闭接收所有的帧
    ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable;//允许接收所有广播帧
    ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable;            //关闭混合模式的地址过滤  
    ETH_InitStructure.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect;//对于组播地址使用完美地址过滤   
    ETH_InitStructure.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect;    //对单播地址使用完美地址过滤 
#ifdef CHECKSUM_BY_HARDWARE
    ETH_InitStructure.ETH_ChecksumOffload = ETH_ChecksumOffload_Enable;             //开启ipv4和TCP/UDP/ICMP的帧校验和卸载   
#endif
    //当我们使用帧校验和卸载功能的时候,一定要使能存储转发模式,存储转发模式中要保证整个帧存储在FIFO中,
    //这样MAC能插入/识别出帧校验值,当真校验正确的时候DMA就可以处理帧,否则就丢弃掉该帧
    ETH_InitStructure.ETH_DropTCPIPChecksumErrorFrame = ETH_DropTCPIPChecksumErrorFrame_Enable; //开启丢弃TCP/IP错误帧
    ETH_InitStructure.ETH_ReceiveStoreForward = ETH_ReceiveStoreForward_Enable;     //开启接收数据的存储转发模式    
    ETH_InitStructure.ETH_TransmitStoreForward = ETH_TransmitStoreForward_Enable;   //开启发送数据的存储转发模式  

    ETH_InitStructure.ETH_ForwardErrorFrames = ETH_ForwardErrorFrames_Disable;         //禁止转发错误帧  
    ETH_InitStructure.ETH_ForwardUndersizedGoodFrames = ETH_ForwardUndersizedGoodFrames_Disable;    //不转发过小的好帧 
    ETH_InitStructure.ETH_SecondFrameOperate = ETH_SecondFrameOperate_Enable;          //打开处理第二帧功能
    ETH_InitStructure.ETH_AddressAlignedBeats = ETH_AddressAlignedBeats_Enable;      //开启DMA传输的地址对齐功能
    ETH_InitStructure.ETH_FixedBurst = ETH_FixedBurst_Enable;                        //开启固定突发功能    
    ETH_InitStructure.ETH_RxDMABurstLength = ETH_RxDMABurstLength_32Beat;             //DMA发送的最大突发长度为32个节拍   
    ETH_InitStructure.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32Beat;            //DMA接收的最大突发长度为32个节拍
    ETH_InitStructure.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_2_1;
    
    ETH_Init(&ETH_InitStructure,LAN8720_PHY_ADDRESS);        //配置ETH
    ETH_DMAITConfig(ETH_DMA_IT_NIS|ETH_DMA_IT_R,ENABLE);      //使能以太网接收中断    
    
    rval=ETH_Init(&ETH_InitStructure,LAN8720_PHY_ADDRESS);        //配置ETH
    if(rval==ETH_SUCCESS)//配置成功
    {
        ETH_DMAITConfig(ETH_DMA_IT_NIS|ETH_DMA_IT_R,ENABLE);      //使能以太网接收中断    
        
//        printf("ETH_DMAITConfig OK\r\n");
    }
    return rval;
}

extern void lwip_pkt_handle(void);        //在lwip_comm.c里面定义
//以太网中断服务函数
void ETH_IRQHandler(void)
{
    while(ETH_GetRxPktSize(DMARxDescToGet)!=0)     //检测是否收到数据包
    { 
        lwip_pkt_handle();        
    }
    ETH_DMAClearITPendingBit(ETH_DMA_IT_R);
    ETH_DMAClearITPendingBit(ETH_DMA_IT_NIS);
}  
//接收一个网卡数据包
//返回值:网络数据包帧结构体
FrameTypeDef ETH_Rx_Packet(void)

    uint32_t framelength=0;
    FrameTypeDef frame={0,0};   
    //检查当前描述符,是否属于ETHERNET DMA(设置的时候)/CPU(复位的时候)
    if((DMARxDescToGet->Status&ETH_DMARxDesc_OWN)!=(uint32_t)RESET)
    {    
        frame.length=ETH_ERROR; 
        if ((ETH->DMASR&ETH_DMASR_RBUS)!=(uint32_t)RESET)  
        { 
            ETH->DMASR = ETH_DMASR_RBUS;//清除ETH DMA的RBUS位 
            ETH->DMARPDR=0;//恢复DMA接收
        }
        return frame;//错误,OWN位被设置了
    }  
    if(((DMARxDescToGet->Status&ETH_DMARxDesc_ES)==(uint32_t)RESET)&& 
    ((DMARxDescToGet->Status & ETH_DMARxDesc_LS)!=(uint32_t)RESET)&&  
    ((DMARxDescToGet->Status & ETH_DMARxDesc_FS)!=(uint32_t)RESET))  
    {       
        framelength=((DMARxDescToGet->Status&ETH_DMARxDesc_FL)>>ETH_DMARxDesc_FrameLengthShift)-4;//得到接收包帧长度(不包含4字节CRC)
         frame.buffer = DMARxDescToGet->Buffer1Addr;//得到包数据所在的位置
    }else framelength=ETH_ERROR;//错误  
    frame.length=framelength; 
    frame.descriptor=DMARxDescToGet;  
    //更新ETH DMA全局Rx描述符为下一个Rx描述符
    //为下一次buffer读取设置下一个DMA Rx描述符
    DMARxDescToGet=(ETH_DMADESCTypeDef*)(DMARxDescToGet->Buffer2NextDescAddr);   
    return frame;  
}
//发送一个网卡数据包
//FrameLength:数据包长度
//返回值:ETH_ERROR,发送失败(0)
//        ETH_SUCCESS,发送成功(1)
uint8_t ETH_Tx_Packet(uint16_t FrameLength)
{   
    //检查当前描述符,是否属于ETHERNET DMA(设置的时候)/CPU(复位的时候)
    if((DMATxDescToSet->Status&ETH_DMATxDesc_OWN)!=(uint32_t)RESET)return ETH_ERROR;//错误,OWN位被设置了 
     DMATxDescToSet->ControlBufferSize=(FrameLength&ETH_DMATxDesc_TBS1);//设置帧长度,bits[12:0]
    DMATxDescToSet->Status|=ETH_DMATxDesc_LS|ETH_DMATxDesc_FS;//设置最后一个和第一个位段置位(1个描述符传输一帧)
      DMATxDescToSet->Status|=ETH_DMATxDesc_OWN;//设置Tx描述符的OWN位,buffer重归ETH DMA
    if((ETH->DMASR&ETH_DMASR_TBUS)!=(uint32_t)RESET)//当Tx Buffer不可用位(TBUS)被设置的时候,重置它.恢复传输
    { 
        ETH->DMASR=ETH_DMASR_TBUS;//重置ETH DMA TBUS位 
        ETH->DMATPDR=0;//恢复DMA发送
    } 
    //更新ETH DMA全局Tx描述符为下一个Tx描述符
    //为下一次buffer发送设置下一个DMA Tx描述符 
    DMATxDescToSet=(ETH_DMADESCTypeDef*)(DMATxDescToSet->Buffer2NextDescAddr);    
    return ETH_SUCCESS;   
}
//得到当前描述符的Tx buffer地址
//返回值:Tx buffer地址
uint32_t ETH_GetCurrentTxBuffer(void)
{  
  return DMATxDescToSet->Buffer1Addr;//返回Tx buffer地址  
}

3.2 打开BSP_LAN8720.h修改为

#ifndef __BSP_LAN8720_H
#define __BSP_LAN8720_H
//#include "BSP_SYS.h"    
#include "stm32f4x7_eth.h"
            
#define LAN8720_PHY_ADDRESS      0x00                //LAN8720 PHY芯片地址.
#define LAN8720_RST                PBout(14)             //LAN8720复位引脚     


extern    ETH_DMADESCTypeDef DMARxDscrTab[ETH_RXBUFNB];    //以太网DMA接收描述符数据结构体指针  
extern    ETH_DMADESCTypeDef DMATxDscrTab[ETH_TXBUFNB];    //以太网DMA发送描述符数据结构体指针   
extern    uint8_t Rx_Buff[ETH_RX_BUF_SIZE*ETH_RXBUFNB];    //以太网底层驱动接收buffers指针   
extern    uint8_t Tx_Buff[ETH_TX_BUF_SIZE*ETH_TXBUFNB];    //以太网底层驱动发送buffers指针 

extern ETH_DMADESCTypeDef  *DMATxDescToSet;            //DMA发送描述符追踪指针
extern ETH_DMADESCTypeDef  *DMARxDescToGet;         //DMA接收描述符追踪指针 
extern ETH_DMA_Rx_Frame_infos *DMA_RX_FRAME_infos;    //DMA最后接收到的帧信息指针
 

extern    uint8_t LAN8720_Init(void);
extern    uint8_t LAN8720_Get_Speed(void);
extern    uint16_t LAN8720_Get_State(void);
extern    uint8_t ETH_MACDMA_Config(void);
extern    FrameTypeDef ETH_Rx_Packet(void);
extern    uint8_t ETH_Tx_Packet(uint16_t FrameLength);
extern    uint32_t ETH_GetCurrentTxBuffer(void);
extern    uint16_t LAN8720_Get_State_TEXT(uint8_t REG);


#endif 

3.3 将BSP_LAN8720.c添加进工程文件并添加头文件路径

3.4 编译一下 一个error,以太网DMA接收中断函数ETH_IRQHandler()函数调用lwip_pkt_handle()函数,而此函数暂时未定义。如果有错误注意刚复制的文件 里面有没有乱码 注意修改

肆、添加LWIP源文件

4.1 Libraries文件夹新建Other_Libraries/LWIP文件夹并将之前解压的lwip-1.4.1文件夹复制到此。整体复制有好多没用的刚开始不知道应该删除那些就别乱动,学会了、能用了再说。

4.2 新建工程目录

4.3 将LWIP/lwip-1.4.1/src/api文件夹下八个文件添加至工程LWIP/API

4.4 将LWIP/lwip-1.4.1/src/core/ipv4文件夹下八个文件添加至工程LWIP/CORE

4.5 将LWIP/lwip-1.4.1/src/core文件夹下16个文件添加至工程LWIP/CORE

4.6 将LWIP/lwip-1.4.1/src/netif文件夹下2个文件添加至工程LWIP/NETIF

4.7 添加刚才三个分组的头文件·

4.8 编译一下 34个error  不要怕缺少点文件,接下来编写这些文件

伍、添加中间文件

准备lwip文件时下载过两个文件这是其中另一个contrib-1.4.1文件中共计五个文件sys_arch.c、sys_arch.h、cc.h、cpu.h、perf.h 为适应不同厂家芯片及实时操作系统写的比较大,无操作系统版需要文件很少,直接拷贝下面写的即可。也是在原子移植好的基础上修修补补。

5.0 建立arch文件夹并建立五个文件

5.1 打开sys_arch.c修改为

/*
 * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
 * All rights reserved. 
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
 * OF SUCH DAMAGE.
 *
 * This file is part of the lwIP TCP/IP stack.
 * 
 * Author: Adam Dunkels <adam@sics.se>
 *
 */
/* lwIP includes. */
#include "lwip/debug.h"
#include "lwip/def.h"
#include "lwip/sys.h"
#include "lwip/mem.h"
#include "BSP_TIMER.h"

//为LWIP提供计时
extern uint32_t lwip_localtime;//lwip本地时间计数器,单位:ms
u32_t sys_now(void){
    return lwip_localtime;
}

5.1 打开sys_arch.h修改为

/*
 * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
 * All rights reserved. 
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
 * OF SUCH DAMAGE.
 *
 * This file is part of the lwIP TCP/IP stack.
 * 
 * Author: Adam Dunkels <adam@sics.se>
 *
 */
#ifndef __ARCH_SYS_ARCH_H__
#define __ARCH_SYS_ARCH_H__ 
#include "arch/cc.h"
 
u32_t sys_now(void);
#endif 

5.2 打开cc.h修改为

/*
 * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
 * All rights reserved. 
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
 * OF SUCH DAMAGE.
 *
 * This file is part of the lwIP TCP/IP stack.
 * 
 * Author: Adam Dunkels <adam@sics.se>
 *
 */
#ifndef __CC_H__
#define __CC_H__

#include "cpu.h"
#include "stdio.h"

/*-------------data type------------------------------------------------------*/

typedef unsigned   char    u8_t;    /* Unsigned 8 bit quantity         */
typedef signed     char    s8_t;    /* Signed    8 bit quantity        */
typedef unsigned   short   u16_t;   /* Unsigned 16 bit quantity        */
typedef signed     short   s16_t;   /* Signed   16 bit quantity        */
typedef unsigned   long    u32_t;   /* Unsigned 32 bit quantity        */
typedef signed     long    s32_t;   /* Signed   32 bit quantity        */
typedef u32_t mem_ptr_t;            /* Unsigned 32 bit quantity        */
typedef int sys_prot_t;

/*-------------critical region protection (depends on uC/OS-II setting)-------*/

#if OS_CRITICAL_METHOD == 1
#define SYS_ARCH_DECL_PROTECT(lev)
#define SYS_ARCH_PROTECT(lev)        CPU_INT_DIS()
#define SYS_ARCH_UNPROTECT(lev)        CPU_INT_EN()
#endif

#if OS_CRITICAL_METHOD == 3  //method 3 is used in this port.
#define SYS_ARCH_DECL_PROTECT(lev)    u32_t lev
#define SYS_ARCH_PROTECT(lev)        lev = OS_CPU_SR_Save()
#define SYS_ARCH_UNPROTECT(lev)        OS_CPU_SR_Restore(lev)
#endif

/*----------------------------------------------------------------------------*/

/* define compiler specific symbols */
#if defined (__ICCARM__)

#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT 
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#define PACK_STRUCT_USE_INCLUDES

#elif defined (__CC_ARM)

#define PACK_STRUCT_BEGIN __packed
#define PACK_STRUCT_STRUCT 
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x

#elif defined (__GNUC__)

#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x

#elif defined (__TASKING__)

#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x

#endif

/*---define (sn)printf formatters for these lwip types, for lwip DEBUG/STATS--*/

#define U16_F "4d"
#define S16_F "4d"
#define X16_F "4x"
#define U32_F "8ld"
#define S32_F "8ld"
#define X32_F "8lx"

/*--------------macros--------------------------------------------------------*/
#ifndef LWIP_PLATFORM_ASSERT
#define LWIP_PLATFORM_ASSERT(x) \
    do \
    {   printf("Assertion \"%s\" failed at line %d in %s\r\n", x, __LINE__, __FILE__); \
    } while(0)
#endif

#ifndef LWIP_PLATFORM_DIAG
#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0)
#endif

#endif /* __CC_H__ */

5.3 打开cpu.h修改为

/*
 * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
 * All rights reserved. 
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
 * OF SUCH DAMAGE.
 *
 * This file is part of the lwIP TCP/IP stack.
 * 
 * Author: Adam Dunkels <adam@sics.se>
 *
 */
#ifndef __CPU_H__
#define __CPU_H__

#define BYTE_ORDER LITTLE_ENDIAN

#endif /* __CPU_H__ */

5.4 打开perf.h修改为

/*
 * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
 * All rights reserved. 
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
 * OF SUCH DAMAGE.
 *
 * This file is part of the lwIP TCP/IP stack.
 * 
 * Author: Adam Dunkels <adam@sics.se>
 *
 */
#ifndef __PERF_H__
#define __PERF_H__

#define PERF_START    /* null definition */
#define PERF_STOP(x)  /* null definition */

#endif /* __PERF_H__ */

5.5 将sys_arch.c添加至工程LWIP/ARCH

5.6 添加中间文件的头文件路径

5.7 将定时器修改为1ms定时器

5.8 修改BSP_TIMER.c文件

5.9 编译一下  还是35个error   如果有其他乱码注意修改

陆、添加LWIP通用文件

LWIP通用文件共三个文件,lwip_comm.c、lwip_comm.c正点原子写的,lwipopts.h裁剪文件根据需要添加

6.1 编写lwip_comm.c文件

#include "lwip_comm.h" 
#include "netif/etharp.h"
#include "lwip/dhcp.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/init.h"
#include "ethernetif.h" 
#include "lwip/timers.h"
#include "lwip/tcp_impl.h"
#include "lwip/ip_frag.h"
#include "lwip/tcpip.h" 
#include "BSP_DEBUG.h" 
#include <stdio.h>
  
__lwip_dev lwipdev;                        //lwip控制结构体 
struct netif lwip_netif;                //定义一个全局的网络接口

extern u32 memp_get_memorysize(void);    //在memp.c里面定义
//extern u8_t *memp_memory;                //在memp.c里面定义.
//extern u8_t *ram_heap;                    //在mem.c里面定义.

u32 TCPTimer=0;            //TCP查询计时器
u32 ARPTimer=0;            //ARP查询计时器
u32 lwip_localtime;        //lwip本地时间计数器,单位:ms


//lwip中mem和memp的内存申请
//返回值:0,成功;
//    其他,失败
//u8 lwip_comm_mem_malloc(void)
//{
//    u32 mempsize;
//    u32 ramheapsize; 
//    mempsize=memp_get_memorysize();            //得到memp_memory数组大小
//    memp_memory=mymalloc(SRAMIN,mempsize);    //为memp_memory申请内存
//    ramheapsize=LWIP_MEM_ALIGN_SIZE(MEM_SIZE)+2*LWIP_MEM_ALIGN_SIZE(4*3)+MEM_ALIGNMENT;//得到ram heap大小
//    ram_heap=mymalloc(SRAMIN,ramheapsize);    //为ram_heap申请内存 
//    if(!memp_memory||!ram_heap)//有申请失败的
//    {
//        lwip_comm_mem_free();
//        return 1;
//    }
//    return 0;    
//}
lwip中mem和memp内存释放
//void lwip_comm_mem_free(void)
//{     
//    myfree(SRAMIN,memp_memory);
//    myfree(SRAMIN,ram_heap);
//}
//lwip 默认IP设置
//lwipx:lwip控制结构体指针
void lwip_comm_default_ip_set(__lwip_dev *lwipx,unsigned char node_id)
{
    
    //MAC地址设置(高三字节固定为:2.0.0,低三字节用STM32唯一ID)
    lwipx->mac[0]=0x43;//高三字节(IEEE称之为组织唯一ID,OUI)地址固定为:2.0.0
    lwipx->mac[1]=0x52;
    lwipx->mac[2]=0x53;
    lwipx->mac[3]=0x43;//低三字节用STM32的唯一ID
    
    lwipx->mac[4]=0x01;

    lwipx->mac[5]=node_id;
    
    //默认本地IP为:192.168.1.30
    lwipx->ip[0]=192;    
    lwipx->ip[1]=168;    
    lwipx->ip[2]=1;    
    lwipx->ip[3]=node_id;
    
    //默认子网掩码:255.255.255.0
    lwipx->netmask[0]=255;    
    lwipx->netmask[1]=255;
    lwipx->netmask[2]=255;
    lwipx->netmask[3]=0;
    
    //默认网关:192.168.1.1
    lwipx->gateway[0]=192;    
    lwipx->gateway[1]=168;
    lwipx->gateway[2]=1;
    lwipx->gateway[3]=1;    
    lwipx->dhcpstatus=0;//没有DHCP    
    
    //默认远端IP为:192.168.1.100
    lwipx->remoteip[0]=192;    
    lwipx->remoteip[1]=168;
    lwipx->remoteip[2]=1;
    lwipx->remoteip[3]=14;

//LWIP初始化(LWIP启动的时候使用)
//返回值:0,成功
//      1,内存错误
//      2,LAN8720初始化失败
//      3,网卡添加失败.
u8 lwip_comm_init(unsigned char node_id)
{
    struct netif *Netif_Init_Flag;        //调用netif_add()函数时的返回值,用于判断网络初始化是否成功
    struct ip_addr ipaddr;              //ip地址
    struct ip_addr netmask;             //子网掩码
    struct ip_addr gw;                  //默认网关 
//    if(ETH_Mem_Malloc())return 1;        //内存申请失败
//    if(lwip_comm_mem_malloc())return 1;    //内存申请失败
    if(LAN8720_Init())return 2;            //初始化LAN8720失败 
    lwip_init();                        //初始化LWIP内核
    lwip_comm_default_ip_set(&lwipdev,node_id);    //设置默认IP等信息


    IP4_ADDR(&ipaddr,lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]);
    IP4_ADDR(&netmask,lwipdev.netmask[0],lwipdev.netmask[1] ,lwipdev.netmask[2],lwipdev.netmask[3]);
    IP4_ADDR(&gw,lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]);
    
    printf("\r\n");
    printf("网卡en的MAC地址为:................%d.%d.%d.%d.%d.%d\r\n",lwipdev.mac[0],lwipdev.mac[1],lwipdev.mac[2],lwipdev.mac[3],lwipdev.mac[4],lwipdev.mac[5]);
    printf("静态IP地址........................%d.%d.%d.%d\r\n",lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]);
    printf("子网掩码..........................%d.%d.%d.%d\r\n",lwipdev.netmask[0],lwipdev.netmask[1],lwipdev.netmask[2],lwipdev.netmask[3]);
    printf("默认网关..........................%d.%d.%d.%d\r\n",lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]);

    Netif_Init_Flag=netif_add(&lwip_netif,&ipaddr,&netmask,&gw,NULL,&ethernetif_init,&ethernet_input);//向网卡列表中添加一个网口
    
    
    if(Netif_Init_Flag==NULL)return 3;//网卡添加失败 
    else//网口添加成功后,设置netif为默认值,并且打开netif网口
    {
        netif_set_default(&lwip_netif); //设置netif为默认网口
        netif_set_up(&lwip_netif);        //打开netif网口
    }
    return 0;//操作OK.
}   

//当接收到数据后调用 
void lwip_pkt_handle(void)
{
  //从网络缓冲区中读取接收到的数据包并将其发送给LWIP处理 
 ethernetif_input(&lwip_netif);
}

//LWIP轮询任务
void lwip_periodic_handle()
{
  //ARP每5s周期性调用一次
  if ((lwip_localtime - ARPTimer) >= ARP_TMR_INTERVAL)
  {
    ARPTimer =  lwip_localtime;
    etharp_tmr();
  }

}

6.2 编写lwip_comm.h文件

#ifndef _LWIP_COMM_H
#define _LWIP_COMM_H 
#include "BSP_LAN8720.h"

#define LWIP_MAX_DHCP_TRIES        4   //DHCP服务器最大重试次数
   
//lwip控制结构体
typedef struct  
{
    u8 mac[6];      //MAC地址
    u8 remoteip[4];    //远端主机IP地址 
    u8 ip[4];       //本机IP地址
    u8 netmask[4];     //子网掩码
    u8 gateway[4];     //默认网关的IP地址
    
    vu8 dhcpstatus;    //dhcp状态 
                    //0,未获取DHCP地址;
                    //1,进入DHCP获取状态
                    //2,成功获取DHCP地址
                    //0XFF,获取失败.
}__lwip_dev;
extern __lwip_dev lwipdev;    //lwip控制结构体

void lwip_pkt_handle(void);
void lwip_periodic_handle(void);
    
void lwip_comm_default_ip_set(__lwip_dev *lwipx,unsigned char node_id);
u8 lwip_comm_mem_malloc(void);
void lwip_comm_mem_free(void);
u8 lwip_comm_init(unsigned char node_id);
void lwip_dhcp_process_handle(void);

#endif

6.2 编写lwipopts.h文件

#ifndef __LWIPOPTS_H__
#define __LWIPOPTS_H__

#define SYS_LIGHTWEIGHT_PROT    0

//NO_SYS==1:不使用操作系统
#define NO_SYS                  1  //不使用UCOS操作系统

//使用4字节对齐模式
#define MEM_ALIGNMENT           4  

//MEM_SIZE:heap内存的大小,如果在应用中有大量数据发送的话这个值最好设置大一点 
#define MEM_SIZE                16000 //内存堆大小

//MEMP_NUM_PBUF:memp结构的pbuf数量,如果应用从ROM或者静态存储区发送大量数据时,这个值应该设置大一点
#define MEMP_NUM_PBUF           10

//MEMP_NUM_UDP_PCB:UDP协议控制块(PCB)数量.每个活动的UDP"连接"需要一个PCB.
#define MEMP_NUM_UDP_PCB        6

//MEMP_NUM_TCP_PCB:同时建立激活的TCP数量
#define MEMP_NUM_TCP_PCB        10

//MEMP_NUM_TCP_PCB_LISTEN:能够监听的TCP连接数量
#define MEMP_NUM_TCP_PCB_LISTEN 6

//MEMP_NUM_TCP_SEG:最多同时在队列中的TCP段数量
#define MEMP_NUM_TCP_SEG        15

//MEMP_NUM_SYS_TIMEOUT:能够同时激活的timeout个数
#define MEMP_NUM_SYS_TIMEOUT    8


/* ---------- Pbuf选项---------- */
//PBUF_POOL_SIZE:pbuf内存池个数. 
#define PBUF_POOL_SIZE          20

//PBUF_POOL_BUFSIZE:每个pbuf内存池大小. 
#define PBUF_POOL_BUFSIZE       512


/* ---------- TCP选项---------- */
#define LWIP_TCP                0  //为1是使用TCP
#define TCP_TTL                 255//生存时间

/*当TCP的数据段超出队列时的控制位,当设备的内存过小的时候此项应为0*/
#define TCP_QUEUE_OOSEQ         0

//最大TCP分段
#define TCP_MSS                 (1500 - 40)      //TCP_MSS = (MTU - IP报头大小 - TCP报头大小

//TCP发送缓冲区大小(bytes).
#define TCP_SND_BUF             (4*TCP_MSS)

//TCP_SND_QUEUELEN: TCP发送缓冲区大小(pbuf).这个值最小为(2 * TCP_SND_BUF/TCP_MSS) 
#define TCP_SND_QUEUELEN        (2* TCP_SND_BUF/TCP_MSS)

//TCP发送窗口
#define TCP_WND                 (2*TCP_MSS)


/* ---------- ICMP选项---------- */
#define LWIP_ICMP                 1 //使用ICMP协议

/* ---------- DHCP选项---------- */
//当使用DHCP时此位应该为1,LwIP 0.5.1版本中没有DHCP服务.
#define LWIP_DHCP               0

/* ---------- UDP选项 ---------- */ 
#define LWIP_UDP                1 //使用UDP服务
#define UDP_TTL                 255 //UDP数据包生存时间


/* ---------- Statistics options ---------- */
#define LWIP_STATS 0
#define LWIP_PROVIDE_ERRNO 1


//STM32F4x7允许通过硬件识别和计算IP,UDP和ICMP的帧校验和
#define CHECKSUM_BY_HARDWARE //定义CHECKSUM_BY_HARDWARE,使用硬件帧校验


#ifdef CHECKSUM_BY_HARDWARE
  //CHECKSUM_GEN_IP==0: 硬件生成IP数据包的帧校验和
  #define CHECKSUM_GEN_IP                 0
  //CHECKSUM_GEN_UDP==0: 硬件生成UDP数据包的帧校验和
  #define CHECKSUM_GEN_UDP                0
  //CHECKSUM_GEN_TCP==0: 硬件生成TCP数据包的帧校验和
  #define CHECKSUM_GEN_TCP                0 
  //CHECKSUM_CHECK_IP==0: 硬件检查输入的IP数据包帧校验和
  #define CHECKSUM_CHECK_IP               0
  //CHECKSUM_CHECK_UDP==0: 硬件检查输入的UDP数据包帧校验和
  #define CHECKSUM_CHECK_UDP              0
  //CHECKSUM_CHECK_TCP==0: 硬件检查输入的TCP数据包帧校验和
  #define CHECKSUM_CHECK_TCP              0
#else
  //CHECKSUM_GEN_IP==1: 软件生成IP数据包帧校验和
  #define CHECKSUM_GEN_IP                 1
  // CHECKSUM_GEN_UDP==1: 软件生成UDOP数据包帧校验和
  #define CHECKSUM_GEN_UDP                1
  //CHECKSUM_GEN_TCP==1: 软件生成TCP数据包帧校验和
  #define CHECKSUM_GEN_TCP                1
  // CHECKSUM_CHECK_IP==1: 软件检查输入的IP数据包帧校验和
  #define CHECKSUM_CHECK_IP               1
  // CHECKSUM_CHECK_UDP==1: 软件检查输入的UDP数据包帧校验和
  #define CHECKSUM_CHECK_UDP              1
  //CHECKSUM_CHECK_TCP==1: 软件检查输入的TCP数据包帧校验和
  #define CHECKSUM_CHECK_TCP              1
#endif


/*
   ----------------------------------------------
   ---------- SequentialAPI选项----------
   ----------------------------------------------
*/

//LWIP_NETCONN==1:使能NETCON函数(要求使用api_lib.c)
#define LWIP_NETCONN                    0

/*
   ------------------------------------
   ---------- Socket API选项----------
   ------------------------------------
*/
//LWIP_SOCKET==1:使能Socket API(要求使用sockets.c)
#define LWIP_SOCKET                     0

#define LWIP_COMPAT_MUTEX               1

#define LWIP_SO_RCVTIMEO                1 //通过定义LWIP_SO_RCVTIMEO使能netconn结构体中recv_timeout,使用recv_timeout可以避免阻塞线程


/*
   ----------------------------------------
   ---------- Lwip调试选项----------
   ----------------------------------------
*/
//#define LWIP_DEBUG                     1 //开启DEBUG选项

#define ICMP_DEBUG                      LWIP_DBG_OFF //开启/关闭ICMPdebug

#endif /* __LWIPOPTS_H__ */

6.2 将lwip_comm.c文件添加至工程HARDWARE中

6.3 添加头文件路径

6.2 编译一下1个error ,未定义ethernetif.h

6.3 向LWIP/lwip-1.4.1/src/include/netif文件夹添加ethernetif.h文件

#ifndef __ETHERNETIF_H__
#define __ETHERNETIF_H__
#include "lwip/err.h"
#include "lwip/netif.h"

//网卡的名字
#define IFNAME0 'e'
#define IFNAME1 'n'
 

err_t ethernetif_init(struct netif *netif);
err_t ethernetif_input(struct netif *netif);
#endif

6.4 修改ethernetif.c文件  可能有空格 格式问题修改一下

#include "netif/ethernetif.h" 
#include "BSP_LAN8720.h"
#include "lwip_comm.h" 
#include "netif/etharp.h"  
#include "string.h"  

//由ethernetif_init()调用用于初始化硬件
//netif:网卡结构体指针 
//返回值:ERR_OK,正常
//       其他,失败
static err_t low_level_init(struct netif *netif)
{
#ifdef CHECKSUM_BY_HARDWARE
    int i; 
#endif 
    netif->hwaddr_len = ETHARP_HWADDR_LEN; //设置MAC地址长度,为6个字节
    //初始化MAC地址,设置什么地址由用户自己设置,但是不能与网络中其他设备MAC地址重复
    netif->hwaddr[0]=lwipdev.mac[0]; 
    netif->hwaddr[1]=lwipdev.mac[1]; 
    netif->hwaddr[2]=lwipdev.mac[2];
    netif->hwaddr[3]=lwipdev.mac[3];
    netif->hwaddr[4]=lwipdev.mac[4];
    netif->hwaddr[5]=lwipdev.mac[5];
    netif->mtu=1500; //最大允许传输单元,允许该网卡广播和ARP功能

    netif->flags = NETIF_FLAG_BROADCAST|NETIF_FLAG_ETHARP|NETIF_FLAG_LINK_UP;
    
    ETH_MACAddressConfig(ETH_MAC_Address0, netif->hwaddr); //向STM32F4的MAC地址寄存器中写入MAC地址
    ETH_DMATxDescChainInit(DMATxDscrTab, Tx_Buff, ETH_TXBUFNB);
    ETH_DMARxDescChainInit(DMARxDscrTab, Rx_Buff, ETH_RXBUFNB);
#ifdef CHECKSUM_BY_HARDWARE     //使用硬件帧校验
    for(i=0;i<ETH_TXBUFNB;i++)    //使能TCP,UDP和ICMP的发送帧校验,TCP,UDP和ICMP的接收帧校验在DMA中配置了
    {
        ETH_DMATxDescChecksumInsertionConfig(&DMATxDscrTab[i], ETH_DMATxDesc_ChecksumTCPUDPICMPFull);
    }
#endif
    ETH_Start(); //开启MAC和DMA                
    return ERR_OK;

//用于发送数据包的最底层函数(lwip通过netif->linkoutput指向该函数)
//netif:网卡结构体指针
//p:pbuf数据结构体指针
//返回值:ERR_OK,发送正常
//       ERR_MEM,发送失败
static err_t low_level_output(struct netif *netif, struct pbuf *p)
{
    u8 res;
    struct pbuf *q;
    int l = 0;
    u8 *buffer=(u8 *)ETH_GetCurrentTxBuffer(); 
    for(q=p;q!=NULL;q=q->next) 
    {
        memcpy((u8_t*)&buffer[l], q->payload, q->len);
        l=l+q->len;
    } 
    res=ETH_Tx_Packet(l); 
    if(res==ETH_ERROR)return ERR_MEM;//返回错误状态
    return ERR_OK;
}  
///用于接收数据包的最底层函数
//neitif:网卡结构体指针
//返回值:pbuf数据结构体指针
static struct pbuf * low_level_input(struct netif *netif)
{  
    struct pbuf *p, *q;
    u16_t len;
    int l =0;
    FrameTypeDef frame;
    u8 *buffer;
    p = NULL;
    frame=ETH_Rx_Packet();
    len=frame.length;//得到包大小
    buffer=(u8 *)frame.buffer;//得到包数据地址 
    p=pbuf_alloc(PBUF_RAW,len,PBUF_POOL);//pbufs内存池分配pbuf
    if(p!=NULL)
    {
        for(q=p;q!=NULL;q=q->next)
        {
            memcpy((u8_t*)q->payload,(u8_t*)&buffer[l], q->len);
            l=l+q->len;
        }    
    }
    frame.descriptor->Status=ETH_DMARxDesc_OWN;//设置Rx描述符OWN位,buffer重归ETH DMA 
    if((ETH->DMASR&ETH_DMASR_RBUS)!=(u32)RESET)//当Rx Buffer不可用位(RBUS)被设置的时候,重置它.恢复传输
    { 
        ETH->DMASR=ETH_DMASR_RBUS;//重置ETH DMA RBUS位 
        ETH->DMARPDR=0;//恢复DMA接收
    }
    return p;
}
//网卡接收数据(lwip直接调用)
//netif:网卡结构体指针
//返回值:ERR_OK,发送正常
//       ERR_MEM,发送失败
err_t ethernetif_input(struct netif *netif)
{
    err_t err;
    struct pbuf *p;
    p=low_level_input(netif);
    if(p==NULL) return ERR_MEM;
    err=netif->input(p, netif);
    if(err!=ERR_OK)
    {
        LWIP_DEBUGF(NETIF_DEBUG,("ethernetif_input: IP input error\n"));
        pbuf_free(p);
        p = NULL;
    } 
    return err;

//使用low_level_init()函数来初始化网络
//netif:网卡结构体指针
//返回值:ERR_OK,正常
//       其他,失败
err_t ethernetif_init(struct netif *netif)
{
    LWIP_ASSERT("netif!=NULL",(netif!=NULL));
#if LWIP_NETIF_HOSTNAME            //LWIP_NETIF_HOSTNAME 
    netif->hostname="lwip";      //初始化名称
#endif 
    netif->name[0]=IFNAME0;     //初始化变量netif的name字段
    netif->name[1]=IFNAME1;     //在文件外定义这里不用关心具体值
    netif->output=etharp_output;//IP层发送数据包函数
    netif->linkoutput=low_level_output;//ARP模块发送数据包函数
    low_level_init(netif);         //底层硬件初始化函数
    return ERR_OK;
}

6.5 修改LWIP/CORE/icmp.c文件   支持硬件帧校验 去掉  如果复制 空格有格式问题

屏蔽10行重新添加下面文件

/* This part of code has been modified by ST's MCD Application Team */
/* To use the Checksum Offload Engine for the putgoing ICMP packets,
   the ICMP checksum field should be set to 0, this is required only for Tx ICMP*/
#ifdef CHECKSUM_BY_HARDWARE
    iecho->chksum = 0;
#else
    /* adjust the checksum */
    if (iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) {
      iecho->chksum += htons(ICMP_ECHO << 8) + 1;
    } else {
      iecho->chksum += htons(ICMP_ECHO << 8);
    }    
#endif

6.6 编译一下

柒、修改main.c并编译下载 

捌、ping一下

8.1 win+r 打开运行窗口  输入cmd打开命令行

8.2 命令行输入 ping 192.168.1.120 -t

8.3 ping通了 暂时成功   网线记得插上

  • 21
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
将RT-Thread和LwIP移植STM32F4平台需要一些步骤,下面是一个简单的指南: 1.下载RT-Thread源代码和LwIP源代码。可以从官方网站获取最新版本。 2.将RT-Thread和LwIP源代码添加到您的工程中。可以直接将源代码文件复制到您的工程目录中,也可以在工程中创建一个新的文件夹,并将源代码添加到该文件夹中。 3.根据您的硬件配置,对STM32F4的寄存器和外设进行初始化。通常,您需要根据硬件手册编写一些初始化代码,以使STM32F4与RT-Thread和LwIP兼容。 4.配置LwIP选项。通过修改lwipopts.h文件,您可以配置LwIP的各种选项,例如IP地址、子网掩码、网关等。 5.在RT-Thread的配置文件rtconfig.h中启用LwIP组件。找到RT-Thread中的lwip组件选项,并确保它被启用。 6.修改RT-Thread的初始化代码,以初始化并启动LwIP。在RT-Thread的应用程序入口函数中,添加初始化LwIP的代码。这包括为LwIP创建一个线程,并为网络接口分配内存等。 7.根据您的需求配置LwIP和RT-Thread的线程、任务和堆栈大小。这些参数的默认值可能不适合您的应用,您可以根据需要进行调整。 8.编译并烧录您的应用程序到STM32F4上。使用合适的编译工具和烧录器,将代码编译成二进制文件,并烧录到STM32F4上。 9.测试和调试。在STM32F4上运行您的应用程序,并使用适当的工具(例如串口终端)检查网络连接。您还可以使用调试器来调试您的应用程序,并解决可能遇到的问题。 这只是一个初步指南,具体的移植过程可能因个人需求和硬件平台的差异而有所不同。对于更深入的了解,建议参考LwIP和RT-Thread的官方文档和社区讨论。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值