STM32F407ZGT6无操作系统移植lwip2.1.3,,具备DHCP功能

news2024/12/26 6:04:38

1.工程添加网络库文件

(1).拷贝文件夹

解压en.stsw-stm32070.zip压缩包,把STM32F4x7_ETH_LwIP_V1.1.1\Libraries\STM32F4x7_ETH_Driver文件夹下的inc和src文件夹拷贝到

STM32F407\FWLIB\STM32F4x7_ETH_Driver文件夹目录下:

(2).重命名头文件

进入STM32F407\FWLIB\STM32F4x7_ETH_Driver\inc文件夹,将stm32f4x7_eth_conf_template.h 重命名为stm32f4x7_eth_conf.h

(3).添加c文件以及头文件路径

(4).修改stm32f407_eth_conf.h内容

#ifndef __STM32F4x7_ETH_CONF_H
#define __STM32F4x7_ETH_CONF_H

#ifdef __cplusplus
 extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"

/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Uncomment the line below when using time stamping and/or IPv4 checksum offload */
#define USE_ENHANCED_DMA_DESCRIPTORS

/* Uncomment the line below if you want to use user defined Delay function
   (for precise timing), otherwise default _eth_delay_ function defined within
   the Ethernet driver is used (less precise timing) */
//如果使用用户自己提供的高精度的延时函数,不注释此行,使用系统提供的低精度的延时函数注释此行
//这里我们使用系统提供的低精度的延时函数,注释此行
//#define USE_Delay
#ifdef USE_Delay
  #include "main.h"                /* Header file where the Delay function prototype is exported */  
  #define _eth_delay_    Delay     /* User can provide more timing precise _eth_delay_ function
                                      ex. use Systick with time base of 10 ms (as done in the provided 
                                      STM32F4x7xx demonstrations) */
#else
  #define _eth_delay_    ETH_Delay /* Default _eth_delay_ function with less precise timing */
#endif

/* Uncomment the line below to allow custom configuration of the Ethernet driver buffers */    
//#define CUSTOM_DRIVER_BUFFERS_CONFIG   

#ifdef  CUSTOM_DRIVER_BUFFERS_CONFIG
/* Redefinition of the Ethernet driver buffers size and count */   
 #define ETH_RX_BUF_SIZE    ETH_MAX_PACKET_SIZE /* buffer size for receive */
 #define ETH_TX_BUF_SIZE    ETH_MAX_PACKET_SIZE /* buffer size for transmit */
 #define ETH_RXBUFNB        20                  /* 20 Rx buffers of size ETH_RX_BUF_SIZE */
 #define ETH_TXBUFNB        5                   /* 5  Tx buffers of size ETH_TX_BUF_SIZE */
#endif

/* PHY configuration section **************************************************/
#ifdef USE_Delay
/* PHY Reset delay */ 
#define PHY_RESET_DELAY    ((uint32_t)0x000000FF)
/* PHY Configuration delay */
#define PHY_CONFIG_DELAY   ((uint32_t)0x00000FFF)
/* Delay when writing to Ethernet registers*/
#define ETH_REG_WRITE_DELAY ((uint32_t)0x00000001)
#else
/* PHY Reset delay */ 
#define PHY_RESET_DELAY    ((uint32_t)0x000FFFFF)
/* PHY Configuration delay */ 
#define PHY_CONFIG_DELAY   ((uint32_t)0x00FFFFFF)
/* Delay when writing to Ethernet registers*/
#define ETH_REG_WRITE_DELAY ((uint32_t)0x0000FFFF)
#endif

/*******************  PHY Extended Registers section : ************************/

/* These values are relatives to DP83848 PHY and change from PHY to another,
   so the user have to update this value depending on the used external PHY */   
//这里提供的是DP83848 PHY,我们使用的为LAN8720A
#ifdef DP83848_PHY
    /* The DP83848 PHY status register  */
    #define PHY_SR                 ((uint16_t)0x10) /* PHY status register Offset */
    #define PHY_SPEED_STATUS       ((uint16_t)0x0002) /* PHY Speed mask */
    #define PHY_DUPLEX_STATUS      ((uint16_t)0x0004) /* PHY Duplex mask */

    /* The DP83848 PHY: MII Interrupt Control Register  */
    #define PHY_MICR               ((uint16_t)0x11) /* MII Interrupt Control Register */
    #define PHY_MICR_INT_EN        ((uint16_t)0x0002) /* PHY Enable interrupts */
    #define PHY_MICR_INT_OE        ((uint16_t)0x0001) /* PHY Enable output interrupt events */

    /* The DP83848 PHY: MII Interrupt Status and Misc. Control Register */
    #define PHY_MISR               ((uint16_t)0x12) /* MII Interrupt Status and Misc. Control Register */
    #define PHY_MISR_LINK_INT_EN   ((uint16_t)0x0020) /* Enable Interrupt on change of link status */
    #define PHY_LINK_STATUS        ((uint16_t)0x2000) /* PHY link status interrupt mask */
#endif
//添加LAN8720A 的代码
#define LAN8720A_PHY
#ifdef  LAN8720A_PHY
    #define LAN8720_PHY_ADDRESS   0x00        
    #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

/* Note : Common PHY registers are defined in stm32f4x7_eth.h file */
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
#ifdef __cplusplus
}
#endif
#endif /* __STM32F4x7_ETH_CONF_H */
/************************ (C) COPYRIGHT STMicroelectroni

(5).编译无错误。

2.添加时钟、延时、中断、串口打印、网络硬件接口文件

(1).目录文件以及工程文件添加截图

(2).定时器代码

//tim2.c
/* Includes ------------------------------------------------------------------*/
#include "tim2.h"
#include "mtdelay.h"
#include <stdio.h>
__IO uint8_t htim2_5ms=0;                       //5ms定时器标志位
//定时器2初始化
void Tim2_Init(void)
{                                                
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);       //TIM2_Clock 84M
  TIM_DeInit(TIM2);
  TIM_TimeBaseStructure.TIM_Period=999;       /* 自动重装载寄存器周期的值(计数值) */
                                              /* 累计 TIM_Period个频率后产生一个更新或者中断 */
  TIM_TimeBaseStructure.TIM_Prescaler= 83;    /* 时钟预分频数   例如:时钟频率=72MHZ/(时钟预分频+1) */
  TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;             /* 采样分频 */
  TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;         /* 向上计数模式 */
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
  TIM_ClearFlag(TIM2, TIM_FLAG_Update);                                /* 清除溢出中断标志 */
  TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
  TIM_Cmd(TIM2, ENABLE);                                                              /* 开启时钟 */
    printf("@Tim2 init success\r\n");
}
/**
  * @简介:   定时器中断回调函数
  * @参数:   无
  * @返回值: 无
  */
void Tim2_Callback(void)
{ 
    static u8 time_count=0;
    Time_Update();
    time_count++;
    if(time_count%5==0)
    {    
        time_count=0;
        htim2_5ms =1;
    }    
}
/* USER CODE END 1 */
//tim2.h
#ifndef __TIM2_H__
#define __TIM2_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"
extern __IO uint8_t htim2_5ms;                       //5ms定时器标志位
void Tim2_Init(void);
void Tim2_Callback(void);
#ifdef __cplusplus
}
#endif
#endif /* __TIM_H__ */

(3).延时代码

//mtdelay.c
#include "mtdelay.h"
#define  SYSTEMTICK_PERIOD_MS 1
__IO u32 systemtime =0;
//系统时间更新函数
void Time_Update(void)
{
  systemtime += SYSTEMTICK_PERIOD_MS;
}
//延时函数 延时时间nCount毫秒
void Delay(uint32_t nCount)
{
    uint32_t timingdelay;
  /* Capture the current local time */
  timingdelay = systemtime + nCount;  
  /* wait until the desired delay finish */  
  while(timingdelay > systemtime)
  {     
  }
}
//mtdelay.h
#ifndef __MTDELAY_H__
#define __MTDELAY_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"
extern __IO u32 systemtime;
void Time_Update(void);
void Delay(uint32_t nCount);
#ifdef __cplusplus
}
#endif
#endif /* __USART_H__ */

(4).中断代码

//mtnvic.c
#include "mtnvic.h"
//中断配置函数
void MT_NVIC_Init(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
    //4位抢占优先级 0位响应优先级
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    //定时器2中断
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;      
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;    
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  NVIC_InitStructure.NVIC_IRQChannel = ETH_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;            
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
    
    //串口6接受回调函数
 NVIC_InitStructure.NVIC_IRQChannel = USART6_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority  = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
    
  NVIC_InitStructure.NVIC_IRQChannel = SDIO_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  // DMA2 STREAMx Interrupt ENABLE
  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
    
    //串口1接受中断
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x4;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
    
    /* Enable CAN1 RX0 interrupt IRQ channel */    
  NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x5;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  /* Enable CAN1 RX1 interrupt IRQ channel */    
  NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x6;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
    /* Enable CAN2 RX0 interrupt IRQ channel */
  NVIC_InitStructure.NVIC_IRQChannel = CAN2_RX0_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x7;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  /* Enable CAN2 RX1 interrupt IRQ channel */
  NVIC_InitStructure.NVIC_IRQChannel = CAN2_RX1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x8;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}
//mtnvic.h
#ifndef __MTNVIC_H__
#define __MTNVIC_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
void MT_NVIC_Init(void);
/* USER CODE BEGIN Prototypes */
#ifdef __cplusplus
}
#endif
#endif /* __USART_H__ */

(5).网络硬件接口文件

//lan8720a.c
#include "lan8720a.h"
#include "mtdelay.h"
#include "lwip/opt.h"  
#include "lwipopts.h"  
#include <stdio.h>

ETH_InitTypeDef ETH_InitStructure;

/* Private functions ---------------------------------------------------------*/
static void ETH_GPIO_Config(void);
static uint32_t ETH_MACDMA_Config(void);
/**
  * @brief  ETH_BSP_Config
  * @param  None
  * @retval None
  */
uint8_t ETH_BSP_Config(void)
{
   uint32_t rc1 = 0;
   uint32_t rc2 = 0;
   /* Configure the GPIO ports for ethernet pins */
   ETH_GPIO_Config();
   /* Configure the Ethernet MAC/DMA */
   rc1=ETH_MACDMA_Config();
    
   if((ETH_ReadPHYRegister(LAN8720_PHY_ADDRESS, PHY_BSR) & PHY_Linked_Status)!=0)
   {
      rc2=1;
   }
    return (rc1&&rc2);
}
/**
  * @brief  Configures the different GPIO ports.
  * @param  None
  * @retval None
  */
static void ETH_GPIO_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  //使能GPIO时钟 RMII接口
    
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_GPIOG , ENABLE);
    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 -------------------> PG11
    ETH_RMII_TXD0 --------------------> PG13
    ETH_RMII_TXD1 --------------------> PG14
    ETH_RESET-------------------------> PD3*/            
    //配置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_13 | GPIO_Pin_14;
    GPIO_Init(GPIOG, &GPIO_InitStructure);
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource11, GPIO_AF_ETH);
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource13, GPIO_AF_ETH);
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource14, GPIO_AF_ETH);
    
    //配置PD3为推完输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    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(GPIOD, &GPIO_InitStructure);
    //LAN8720_RST=0;                    //硬件复位LAN8720
    GPIO_ResetBits(GPIOD, GPIO_Pin_3);
    Delay(50);    //delay_ms(50);    
    //LAN8720_RST=1;                     //复位结束 
    GPIO_SetBits(GPIOD, GPIO_Pin_3);
}

/**
  * @brief  Configures the Ethernet Interface
  * @param  None
  * @retval None
  */
static uint32_t ETH_MACDMA_Config(void)
{
    uint32_t revalue;
  /* Enable ETHERNET clock  */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_ETH_MAC | RCC_AHB1Periph_ETH_MAC_Tx |  RCC_AHB1Periph_ETH_MAC_Rx, ENABLE);               
  /* Reset ETHERNET on AHB Bus */
  ETH_DeInit();
  /* Software reset */
  ETH_SoftwareReset();
  /* Wait for software reset */
  while (ETH_GetSoftwareResetStatus() == SET);
  /* ETHERNET Configuration --------------------------------------------------*/
  /* Call ETH_StructInit if you don't like to configure all ETH_InitStructure parameter */
  ETH_StructInit(&ETH_InitStructure);
  /* Fill ETH_InitStructure parametrs */
  /*------------------------   MAC   -----------------------------------*/
  ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable;
  //ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Disable; 
  //ETH_InitStructure.ETH_Speed = ETH_Speed_100M;
  //ETH_InitStructure.ETH_Mode = ETH_Mode_FullDuplex;   

  ETH_InitStructure.ETH_LoopbackMode = ETH_LoopbackMode_Disable;
  ETH_InitStructure.ETH_RetryTransmission = ETH_RetryTransmission_Disable;
  ETH_InitStructure.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable;
  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;
#endif
  /*------------------------   DMA   -----------------------------------*/  
  /* When we use the Checksum offload feature, we need to enable the Store and Forward mode:
  the store and forward guarantee that a whole frame is stored in the FIFO, so the MAC can insert/verify the checksum, 
  if the checksum is OK the DMA can handle the frame otherwise the frame is dropped */
  ETH_InitStructure.ETH_DropTCPIPChecksumErrorFrame = ETH_DropTCPIPChecksumErrorFrame_Enable;
  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;
  ETH_InitStructure.ETH_FixedBurst = ETH_FixedBurst_Enable;
  ETH_InitStructure.ETH_RxDMABurstLength = ETH_RxDMABurstLength_32Beat;
  ETH_InitStructure.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32Beat;
  ETH_InitStructure.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_2_1;

  /* Configure Ethernet */
  revalue = ETH_Init(&ETH_InitStructure, LAN8720_PHY_ADDRESS);
    
    ETH_DMAITConfig(ETH_DMA_IT_NIS|ETH_DMA_IT_R,ENABLE);      //使能以太网接收中断    
    
    return  revalue;
}
//lan8720a.h
#ifndef __LAN8720A_H
#define __LAN8720A_H

#ifdef __cplusplus
 extern "C" {
#endif
#include "stm32f4xx.h"
#include "stm32f4x7_eth.h"

extern ETH_InitTypeDef ETH_InitStructure;
uint8_t ETH_BSP_Config(void);
#ifdef __cplusplus
}
#endif
#endif 

(6).串口打印文件

//usart1.c
/* Includes ------------------------------------------------------------------*/
#include "usart1.h"
#include <stdio.h>
#include "string.h"

#define USART1_TX_BUF_SIZE 100

uint8_t USART1_TX_Buff[USART1_TX_BUF_SIZE]={0};

static unsigned char RxBuffer[5]={0};              //接收数据缓存

extern char mainusart1recv[5];

static    void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
  /* Connect PXx to USARTx_Rx*/
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
  /* Configure USARTx_Tx as alternate function push-pull */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  /* Configure USARTx_Rx as input floating */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
}
    
    
//串口1初始化函数
void Usart1_Init(uint32_t BaudRate)
{
  USART_InitTypeDef USART_InitStructure;
  DMA_InitTypeDef  DMA_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
  GPIO_Configuration();
  /* USARTx configured as follow:
        - BaudRate = 115200 baud  
        - Word Length = 8 Bits
        - One Stop Bit
        - No parity
        - Hardware flow control disabled (RTS and CTS signals)
        - Receive and transmit enabled
  */
  USART_InitStructure.USART_BaudRate =115200;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_Init(USART1, &USART_InitStructure);
  
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);
  DMA_Cmd(DMA2_Stream7, DISABLE);
  DMA_DeInit(DMA2_Stream7);
  DMA_InitStructure.DMA_Channel                = DMA_Channel_4;
  DMA_InitStructure.DMA_PeripheralBaseAddr     = (uint32_t)&USART1->DR;            //
  DMA_InitStructure.DMA_Memory0BaseAddr        = (uint32_t)USART1_TX_Buff;       //
  DMA_InitStructure.DMA_DIR                    = DMA_DIR_MemoryToPeripheral;
  DMA_InitStructure.DMA_BufferSize             = USART1_TX_BUF_SIZE; 
  DMA_InitStructure.DMA_PeripheralInc          = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc              = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize     = DMA_PeripheralDataSize_Byte;
  DMA_InitStructure.DMA_MemoryDataSize         = DMA_MemoryDataSize_Byte;
  DMA_InitStructure.DMA_Mode                   = DMA_Mode_Normal;
  DMA_InitStructure.DMA_Priority               = DMA_Priority_VeryHigh;
  DMA_InitStructure.DMA_FIFOMode               = DMA_FIFOMode_Disable;
  DMA_InitStructure.DMA_FIFOThreshold          = DMA_FIFOThreshold_1QuarterFull;
  DMA_InitStructure.DMA_MemoryBurst            = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst        = DMA_PeripheralBurst_Single;
  DMA_Init(DMA2_Stream7, &DMA_InitStructure);
  
  DMA_ClearFlag(DMA2_Stream7,DMA_FLAG_TCIF7); 
  USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
  DMA_Cmd(DMA2_Stream7, DISABLE);
    
  USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
  USART_Cmd(USART1, ENABLE); 
  printf("@usart1 init success\r\n");
}

//串口1DMA 发送数据函数
void DMA_USART1_Send(u8 *data,u16 size)
{
    memcpy(USART1_TX_Buff,data,size);
    DMA_ClearFlag(DMA2_Stream7,DMA_FLAG_TCIF7); 
    while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE);    
    DMA_SetCurrDataCounter(DMA2_Stream7,size);        
    DMA_Cmd(DMA2_Stream7,ENABLE);                        
}
//==================================================================
//功能:     UART1中断回调函数
//参数:     uint8_t usartRxBuffer 接受中断的数据
//返回值: 空
//修改记录:
//==================================================================
void Usart1_Callbcak(uint8_t usartRxBuffer)
{
    static uint8_t BuffCnt = 0;
    RxBuffer[BuffCnt] = usartRxBuffer;
    //if(RxBuffer[0]=='r')
    {
        BuffCnt++;
    }
    if(BuffCnt == 5)
    {
        //resetPlatfromPara(RxBuffer);
        memcpy(mainusart1recv,RxBuffer,5);
        memset(RxBuffer,0,5);
        BuffCnt = 0;
    }
}
int fputc(int ch,FILE *p) 
{
 USART_SendData(USART1,(u8)ch);
 while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
 return ch;
}
//usart1.h
#ifndef __USART1_H__
#define __USART1_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
void Usart1_Init(uint32_t BaudRate);
void DMA_USART1_Send(u8 *data,u16 size);
void Usart1_Callbcak(uint8_t usartRxBuffer);
/* USER CODE BEGIN Prototypes */
#ifdef __cplusplus
}
#endif
#endif /* __USART_H__ */

3.工程添加LWIP文件

(1).拷贝LWIP文件夹

解压lwip-2.1.3.zip压缩包,把lwip-2.1.3\src文件夹下的api、apps、core、include、netif文件夹拷贝到工程STM32F407\Middlewares\Lwip_2_1_3目录下

(2)将STM32F407\Middlewares\Lwip_2_1_3\api文件夹下的9个文件加至工程

(3)将STM32F407\Middlewares\Lwip_2_1_3\core文件夹下的20个文件加至工程

(4)将STM32F407\Middlewares\Lwip_2_1_3\core\ipv4文件夹下的8个文件加至工程

(5)将STM32F407\Middlewares\Lwip_2_1_3\netif文件夹下的7个文件加至工程

(6).添加LWIP头文件目录

4.添加contrib中的文件

(1).拷贝.h头文件夹

解压contrib-2.1.0.zip压缩包,将contrib-2.1.0\ports\win32\include\arch文件夹的文件复制到STM32F407\Middlewares\Lwip_2_1_3\lwip_arch\arch文件夹中

(2).拷贝lwipopts.h文件

将contrib-2.1.0\examples\example_app文件夹中的lwipopts.h文件复制到STM32F407\Middlewares\Lwip_2_1_3\lwip_arch\arch文件夹中

(3).拷贝sys_arch.c文件

将contrib-2.1.0\ports\win32文件夹中的sys_arch.c文件复制到STM32F407\Middlewares\Lwip_2_1_3\lwip_arch\src文件夹中

(4).拷贝ethernetif.c文件

contrib-2.1.0\examples\ethernetif文件夹中的ethernetif.c文件复制到STM32F407\Middlewares\Lwip_2_1_3\lwip_arch\src文件夹中

(5).创建ethernetif.h文件

在STM32F407\Middlewares\Lwip_2_1_3\lwip_arch\arch中创建ethernetif.h文件

(6).添加工程文件

5.修改contrib中的文件

(1).修改cc.h文件

#ifndef __CC_H__
#define __CC_H__
#include <stdio.h>
#if SYSTEM_SUPPORT_OS
#include "maintask.h"
#endif
typedef int sys_prot_t;
#if defined (__GNUC__) & !defined (__CC_ARM)
#define LWIP_TIMEVAL_PRIVATE 0
#include <sys/time.h>
#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 (__GNUC__)
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#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 (__TASKING__)
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#endif
#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__ */

(2)修改ethernetif.h和ethernetif.c文件

//ethernetif.c
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/timeouts.h"
#include "netif/etharp.h"
#include "lwip/err.h"
#include "ethernetif.h"
#include "stm32f4x7_eth.h"
#include "string.h"
#include <stdio.h>
//网卡名
#define IFNAME0 's'
#define IFNAME1 't'

//以太网Rx & Tx DMA描述符
extern ETH_DMADESCTypeDef  DMARxDscrTab[ETH_RXBUFNB], DMATxDscrTab[ETH_TXBUFNB];
//以太网收发缓冲区
extern uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE],Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE]; 
//跟踪当前发送和接收描述符的全局指针
extern ETH_DMADESCTypeDef *DMATxDescToSet,*DMARxDescToGet;
//最后接收帧信息的全局指针
extern ETH_DMA_Rx_Frame_infos *DMA_RX_FRAME_infos;

/**
* In this function, the hardware should be initialized.
* Called from ethernetif_init().
*
* @param netif the already initialized lwip network interface structure
*        for this ethernetif
*/
static void low_level_init(struct netif *netif)
{
    uint32_t i;
 netif->hwaddr_len = ETHARP_HWADDR_LEN;//设置nettif MAC硬件地址长度
 //初始化MAC地址,设置什么地址由用户自己设置,但是不能与网络中其他设备MAC地址重复
 netif->hwaddr[0]=12; 
 netif->hwaddr[1]=34; 
 netif->hwaddr[2]=56;
 netif->hwaddr[3]=78;   
 netif->hwaddr[4]=10;
 netif->hwaddr[5]=21;
 netif->mtu = 1500;//nettif最大传输单位
 //网卡状态信息标志位,是很重要的控制字段,它包括网卡功能使能、广播
 netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP|NETIF_FLAG_LINK_UP;//接受广播地址和ARP流量

    ETH_MACAddressConfig(ETH_MAC_Address0, netif->hwaddr);//初始化以太网MAC中的MAC地址 
    ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);//初始化Tx描述符列表:链式模式
    ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);//初始化Rx描述符列表:链式模式
    //初始化Tx描述符列表:链式模式
    { 
    for(i=0; i<ETH_RXBUFNB; i++)
    {
    ETH_DMARxDescReceiveITConfig(&DMARxDscrTab[i], ENABLE);
    }
    }
#ifdef CHECKSUM_BY_HARDWARE
    //使能Tx帧的校验和插入
    {
    for(i=0; i<ETH_TXBUFNB; i++)
    {
    ETH_DMATxDescChecksumInsertionConfig(&DMATxDscrTab[i], ETH_DMATxDesc_ChecksumTCPUDPICMPFull);
    }
    } 
#endif
    ETH_Start();//使能MAC和DMA传输和接收  
}
/**
* This function should do the actual transmission of the packet. The packet is
* contained in the pbuf that is passed to the function. This pbuf
* might be chained.
*
* @param netif the lwip network interface structure for this ethernetif
* @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
* @return ERR_OK if the packet could be sent
*         an err_t value if the packet couldn't be sent
*
* @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
*       strange results. You might consider waiting for space in the DMA queue
*       to become availale since the stack doesn't retry to send a packet
*       dropped because of memory failure (except for the TCP timers).
*/

static err_t low_level_output(struct netif *netif, struct pbuf *p)
{
    err_t errval;
    struct pbuf *q;
    uint8_t *buffer = (uint8_t *)(DMATxDescToSet->Buffer1Addr);
 __IO ETH_DMADESCTypeDef *DmaTxDesc;
    uint16_t framelength = 0;
    uint32_t bufferoffset = 0;
    uint32_t byteslefttocopy = 0;
    uint32_t payloadoffset = 0;
    
 DmaTxDesc = DMATxDescToSet;
 bufferoffset = 0;
    
#if ETH_PAD_SIZE
 pbuf_remove_header(p, ETH_PAD_SIZE); /* drop the padding word */
#endif        
    for(q = p; q != NULL; q = q->next)//从pbuf中拷贝要发送的数据 
    {
    //判断此发送描述符是否有效,即判断此发送描述符是否归以太网DMA所有
    if((DmaTxDesc->Status & ETH_DMATxDesc_OWN) != (uint32_t)RESET)
    {
    errval=ERR_USE;
    goto error;
    }
    //获取当前lwIP缓冲区中的字节
    byteslefttocopy = q->len;
    payloadoffset = 0;
    /*将pbuf中要发送的数据写入到以太网发送描述符中,有时候我们要发送的数据可能大于一个以太网
    描述符的Tx Buffer,因此我们需要分多次将数据拷贝到多个发送描述符中*/
    while((byteslefttocopy+bufferoffset)>ETH_TX_BUF_SIZE)
    {
    //将数据拷贝到以太网发送描述符的Tx Buffer中
    memcpy((u8_t*)((u8_t*)buffer+bufferoffset),(u8_t*)((u8_t*)q->payload+payloadoffset),(ETH_TX_BUF_SIZE-bufferoffset));
    //DmaTxDsc指向下一个发送描述符
    DmaTxDesc = (ETH_DMADESCTypeDef *)(DmaTxDesc->Buffer2NextDescAddr);
    //检查新的发送描述符是否有效
    if((DmaTxDesc->Status&ETH_DMATxDesc_OWN)!=(u32)RESET)
    {
    errval = ERR_USE;
    goto error;
    }
    buffer = (u8 *)(DmaTxDesc->Buffer1Addr);//更新buffer地址,指向新的发送描述符的Tx Buffer
    byteslefttocopy = byteslefttocopy - (ETH_TX_BUF_SIZE - bufferoffset);
    payloadoffset = payloadoffset + (ETH_TX_BUF_SIZE - bufferoffset);
    framelength = framelength + (ETH_TX_BUF_SIZE - bufferoffset);
    bufferoffset = 0;
    }
    
    //拷贝剩余的数据
    memcpy( (u8_t*)((u8_t*)buffer+bufferoffset),(u8_t*)((u8_t*)q->payload+payloadoffset),byteslefttocopy );
    bufferoffset = bufferoffset + byteslefttocopy;
    framelength = framelength + byteslefttocopy;
    }
    //当所有要发送的数据都放进发送描述符的Tx Buffer以后就可发送此帧了
    ETH_Prepare_Transmit_Descriptors(framelength);
 errval = ERR_OK;
error:
    //发送缓冲区发生下溢,一旦发送缓冲区发生下溢TxDMA会进入挂起状态
    if((ETH->DMASR&ETH_DMASR_TUS)!= (uint32_t)RESET)
    {    
    ETH->DMASR = ETH_DMASR_TUS;//清除下溢标志
    /* 当发送帧中出现下溢错误的时候TxDMA会挂起,这时候需要向DMATPDR寄存器
    随便写入一个值来将其唤醒,此处我们写0 */
    ETH->DMATPDR=0;
    }
    return errval;
}
/**
* Should allocate a pbuf and transfer the bytes of the incoming
* packet from the interface into the pbuf.
*
* @param netif the lwip network interface structure for this ethernetif
* @return a pbuf filled with the received packet (including MAC header)
*         NULL on memory error
*/
static struct pbuf * low_level_input(struct netif *netif)
{
    struct pbuf *p= NULL, *q=NULL;
    u32_t len;
 FrameTypeDef frame;
 u8 *buffer;
 __IO ETH_DMADESCTypeDef *DMARxDesc;
    uint32_t bufferoffset = 0;
    uint32_t payloadoffset = 0;
    uint32_t byteslefttocopy = 0;
    uint32_t i=0;  
    
 frame = ETH_Get_Received_Frame_interrupt();//接收一帧数据帧
    //获取数据包的大小并将其放入"len"变量中
 len = frame.length;
 buffer = (u8 *)frame.buffer;
    //从Lwip缓冲池中分配一个pbuf链
    if(len > 0) p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
    else return p;
    //pbuf链分配成功
    if (p != NULL)
    {
    DMARxDesc = frame.descriptor;//获取接收描述符链表中的第一个描述符 
    bufferoffset = 0;
    for(q = p; q != NULL; q = q->next)
    {
    byteslefttocopy = q->len;
    payloadoffset = 0;
    
    //检查当前pbuf中要复制的字节长度是否大于Rx缓冲区大小
    while( (byteslefttocopy + bufferoffset) > ETH_RX_BUF_SIZE )
    {
    //将数据复制到pbuf
    memcpy( (u8_t*)((u8_t*)q->payload + payloadoffset),(u8_t*)((u8_t*)buffer + bufferoffset), (ETH_RX_BUF_SIZE - bufferoffset));
    
    //指向下一个描述符
    DMARxDesc = (ETH_DMADESCTypeDef *)(DMARxDesc->Buffer2NextDescAddr);
    buffer = (unsigned char *)(DMARxDesc->Buffer1Addr);
    
    byteslefttocopy = byteslefttocopy - (ETH_RX_BUF_SIZE - bufferoffset);
    payloadoffset = payloadoffset + (ETH_RX_BUF_SIZE - bufferoffset);
    bufferoffset = 0;
    }
    
    //复制pbuf中的剩余数据
    memcpy( (u8_t*)((u8_t*)q->payload + payloadoffset),(u8_t*)((u8_t*)buffer + bufferoffset), byteslefttocopy);
    bufferoffset = bufferoffset + byteslefttocopy;
    }
    }
 DMARxDesc =frame.descriptor;//向DMA释放描述符
    //在Rx描述符中设置自己的位:将缓冲区返回给DMA
    for(i=0; i<DMA_RX_FRAME_infos->Seg_Count; i++)
    {  
    DMARxDesc->Status = ETH_DMARxDesc_OWN;
    DMARxDesc = (ETH_DMADESCTypeDef *)(DMARxDesc->Buffer2NextDescAddr);
    }
 DMA_RX_FRAME_infos->Seg_Count =0;//清除段计数
  
    //当设置Rx缓冲区不可用标志时:清除它并恢复接收
    if((ETH->DMASR & ETH_DMASR_RBUS) != (u32)RESET)  
    {
    ETH->DMASR = ETH_DMASR_RBUS;//清除接收缓冲区不可用标志
    /* 当接收缓冲区不可用的时候 RxDMA 会进去挂起状态,
    通过向 DMARPDR 写入任意一个值来唤醒 Rx DMA */
    ETH->DMARPDR = 0;
    }
    return p;
}
/**
* This function is the ethernetif_input task, it is processed when a packet 
* is ready to be read from the interface. It uses the function low_level_input() 
* that should handle the actual reception of bytes from the network
* interface. Then the type of the received packet is determined and
* the appropriate input function is called.
*
* @param netif the lwip network interface structure for this ethernetif
*/
err_t ethernetif_input(struct netif *netif)
{
    struct pbuf *p;
    err_t err;
    /* move received packet into a new pbuf */
    p = low_level_input(netif);
    /* no packet could be read, silently ignore this */
    if (p == NULL) return ERR_MEM;
    /* entry point to the LwIP stack */
    err = netif->input(p, netif);
    if (err != ERR_OK)
    {
    LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
    pbuf_free(p);
    }
    return err;
}
/**
* Should be called at the beginning of the program to set up the
* network interface. It calls the function low_level_init() to do the
* actual setup of the hardware.
*
* This function should be passed as a parameter to netif_add().
*
* @param netif the lwip network interface structure for this ethernetif
* @return ERR_OK if the loopif is initialized
*         ERR_MEM if private data couldn't be allocated
*         any other err_t on error
*/
err_t ethernetif_init(struct netif *netif)
{
  LWIP_ASSERT("netif != NULL", (netif != NULL));
#if LWIP_NETIF_HOSTNAME
  /* Initialize interface hostname */
  netif->hostname = "lwip";
#endif /* LWIP_NETIF_HOSTNAME */
  netif->name[0] = IFNAME0;
  netif->name[1] = IFNAME1;
  netif->output = etharp_output;
  netif->linkoutput = low_level_output;
  /* initialize the hardware */
  low_level_init(netif);
  return ERR_OK;
}
//ethernetif.h
#ifndef __ETHERNETIF_H
#define __ETHERNETIF_H

#ifdef __cplusplus
 extern "C" {
#endif

#include "lwip/err.h"
#include "lwip/netif.h"
err_t ethernetif_init(struct netif *netif);
err_t ethernetif_input(struct netif *netif);

#ifdef __cplusplus
}
#endif

#endif

(3).修改sys_arch.h和sys_arch.c文件

//sys_arch.c
#include <stdlib.h>
#include <stdio.h> 
#include "mtdelay.h"
#include "sys_arch.h"

uint32_t sys_now(void)
{
  return (uint32_t)systemtime;
}
//sys_arch.h
#ifndef LWIP_ARCH_SYS_ARCH_H
#define LWIP_ARCH_SYS_ARCH_H
#include "stm32f4xx.h"
/* HANDLE is used for sys_sem_t but we won't include windows.h */
struct _sys_sem {
  void *sem;
};
typedef struct _sys_sem sys_sem_t;
uint32_t sys_now(void);
#define sys_sem_valid_val(sema) (((sema).sem != NULL)  && ((sema).sem != (void*)-1))
#define sys_sem_valid(sema) (((sema) != NULL) && sys_sem_valid_val(*(sema)))
#define sys_sem_set_invalid(sema) ((sema)->sem = NULL)

/* HANDLE is used for sys_mutex_t but we won't include windows.h */
struct _sys_mut {
  void *mut;
};
typedef struct _sys_mut sys_mutex_t;
#define sys_mutex_valid_val(mutex) (((mutex).mut != NULL)  && ((mutex).mut != (void*)-1))
#define sys_mutex_valid(mutex) (((mutex) != NULL) && sys_mutex_valid_val(*(mutex)))
#define sys_mutex_set_invalid(mutex) ((mutex)->mut = NULL)

#ifndef MAX_QUEUE_ENTRIES
#define MAX_QUEUE_ENTRIES 100
#endif
struct lwip_mbox {
  void* sem;
  void* q_mem[MAX_QUEUE_ENTRIES];
  uint32_t head, tail;
};
typedef struct lwip_mbox sys_mbox_t;
#define SYS_MBOX_NULL NULL
#define sys_mbox_valid_val(mbox) (((mbox).sem != NULL)  && ((mbox).sem != (void*)-1))
#define sys_mbox_valid(mbox) ((mbox != NULL) && sys_mbox_valid_val(*(mbox)))
#define sys_mbox_set_invalid(mbox) ((mbox)->sem = NULL)

/* DWORD (thread id) is used for sys_thread_t but we won't include windows.h */
typedef uint32_t sys_thread_t;

sys_sem_t* sys_arch_netconn_sem_get(void);
void sys_arch_netconn_sem_alloc(void);
void sys_arch_netconn_sem_free(void);
#define LWIP_NETCONN_THREAD_SEM_GET()   sys_arch_netconn_sem_get()
#define LWIP_NETCONN_THREAD_SEM_ALLOC() sys_arch_netconn_sem_alloc()
#define LWIP_NETCONN_THREAD_SEM_FREE()  sys_arch_netconn_sem_free()

#define LWIP_EXAMPLE_APP_ABORT() lwip_win32_keypressed()
int lwip_win32_keypressed(void);

#endif /* LWIP_ARCH_SYS_ARCH_H */

6.工程中的其他文件介绍

(1).lwipconf.c和lwipconf.h文件

//lwipconf.c
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/tcp.h"
#include "lwip/tcpip.h"
#include "lwip/udp.h"
#include "netif/etharp.h"
#include "lwip/dhcp.h"
#include "lwip/init.h"
#include "lwip/timeouts.h"
#include "lwip/netif.h"
#include "mtdelay.h"
#include "stm32f4x7_eth.h"
#include "sys_arch.h"
#include "ethernetif.h"
#include "lwipconf.h"
#include "lan8720a.h"
#include "lwipopts.h"
#include <stdio.h>

#if LWIP_TCP
uint32_t TCPTimer = 0;
#endif
uint32_t ARPTimer = 0;
uint32_t LinkTimer = 0; 
#if LWIP_DHCP
uint32_t DHCPfineTimer = 0;                    //DHCP精细处理计时器
uint32_t DHCPcoarseTimer = 0;                    //DHCP精细处理计时器 
uint8_t g_lwip_dhcp_state = LWIP_DHCP_START; //DHCP状态初始化
#endif
              
//检测PHY链路状态的实际间隔(单位:ms)
#ifndef LINK_TIMER_INTERVAL
#define LINK_TIMER_INTERVAL        1000
#endif


Lwip_Dhcp_Struct g_lwip_dhcp_struct;    //lwip控制结构体         
struct netif g_lwip_netif;              //定义一个全局的网络接口
uint8_t eth_link_status =0;

void lwip_dhcp_process(void);

/**
  * @breif    lwip 默认IP设置
  * @param    lwipx: lwip控制结构体指针
  * @retval    无
  */
static void lwip_comm_default_ip_set(Lwip_Dhcp_Struct *lwipx)
{
    //默认远端IP为:192.168.0.120
    lwipx->remoteip[0] = 192;
    lwipx->remoteip[1] = 168;
    lwipx->remoteip[2] = 0;
    lwipx->remoteip[3] = 120;
    //默认本地IP为:192.168.0.30
    lwipx->ip[0] = 192;
    lwipx->ip[1] = 168;
    lwipx->ip[2] = 0;
    lwipx->ip[3] = 30;
    //默认子网掩码: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] = 0;
    lwipx->gateway[3] = 1;
    lwipx->canuse = 0;
}

/**
  * @breif    LWIP初始化(LWIP启动的时候使用)
  * @param    无
  * @retval    0,成功
            1,内存错误
            2,以太网芯片初始化失败
            3,网卡添加失败.
  */
uint8_t LwIP_Init(void)
{
    ip_addr_t ipaddr;                //ip地址
    ip_addr_t netmask;            //子网掩码
    ip_addr_t gw;                      //默认网关
    uint8_t revalue=0;
 revalue = ETH_BSP_Config();    //初始化LAN8720 
    lwip_init();                          //初始化LWIP内核
    lwip_comm_default_ip_set(&g_lwip_dhcp_struct);//设置默认IP等信息
#if LWIP_DHCP        //使用动态IP
    ipaddr.addr = 0;
    netmask.addr = 0;
    gw.addr = 0;
#else                //使用静态IP
    IP4_ADDR(&ipaddr,g_lwip_dhcp_struct.ip[0],g_lwip_dhcp_struct.ip[1],g_lwip_dhcp_struct.ip[2],g_lwip_dhcp_struct.ip[3]);
    IP4_ADDR(&netmask,g_lwip_dhcp_struct.netmask[0],g_lwip_dhcp_struct.netmask[1] ,g_lwip_dhcp_struct.netmask[2],g_lwip_dhcp_struct.netmask[3]);
    IP4_ADDR(&gw,g_lwip_dhcp_struct.gateway[0],g_lwip_dhcp_struct.gateway[1],g_lwip_dhcp_struct.gateway[2],g_lwip_dhcp_struct.gateway[3]);
    printf("静态IP地址........%d.%d.%d.%d\r\n",g_lwip_dhcp_struct.ip[0],g_lwip_dhcp_struct.ip[1],g_lwip_dhcp_struct.ip[2],g_lwip_dhcp_struct.ip[3]);
    printf("子网掩码..........%d.%d.%d.%d\r\n",g_lwip_dhcp_struct.netmask[0],g_lwip_dhcp_struct.netmask[1],g_lwip_dhcp_struct.netmask[2],g_lwip_dhcp_struct.netmask[3]);
    printf("默认网关..........%d.%d.%d.%d\r\n",g_lwip_dhcp_struct.gateway[0],g_lwip_dhcp_struct.gateway[1],g_lwip_dhcp_struct.gateway[2],g_lwip_dhcp_struct.gateway[3]);
#endif
    netif_add(&g_lwip_netif,&ipaddr,&netmask,&gw,NULL,&ethernetif_init,&ethernet_input);//向网卡列表中添加一个网口      
    g_lwip_dhcp_struct.canuse=0;    //DHCP标记为0
    netif_set_default(&g_lwip_netif);//设置netif为默认网口
        if(revalue)
      {
                g_lwip_netif.flags |= NETIF_FLAG_LINK_UP;
                netif_set_up(&g_lwip_netif);//打开netif网口
#if LWIP_DHCP
        g_lwip_dhcp_state = LWIP_DHCP_START;
#endif
       }
       else
       {
        netif_set_down(&g_lwip_netif);
#if LWIP_DHCP
        g_lwip_dhcp_state = LWIP_DHCP_LINK_DOWN;
#endif 
       }
    return 0;//操作OK.
}


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

/**
  * @brief  This function handles Ethernet link status callback.
  * @param  None
  * @retval None
  */
void ETH_link_callback(struct netif *netif)
{
    __IO uint32_t timeout = 0;
    uint32_t tmpreg;
    uint16_t RegValue;
    ip_addr_t ipaddr;
    ip_addr_t netmask;
    ip_addr_t gw;
    if (netif_is_link_up(netif))
    {
        /* Restart the auto-negotiation */
        if (ETH_InitStructure.ETH_AutoNegotiation != ETH_AutoNegotiation_Disable) 
                {
            /* Reset Timeout counter */
            timeout = 0;
            /* Enable auto-negotiation */
            ETH_WritePHYRegister(LAN8720_PHY_ADDRESS, PHY_BCR,PHY_AutoNegotiation);
            /* Wait until the auto-negotiation will be completed */
            do {
                timeout++;
            } while (!(ETH_ReadPHYRegister(LAN8720_PHY_ADDRESS, PHY_BSR)&PHY_AutoNego_Complete)&&(timeout<(uint32_t)PHY_READ_TO));
            /* Reset Timeout counter */
            timeout = 0;
            /* Read the result of the auto-negotiation */
            RegValue = ETH_ReadPHYRegister(LAN8720_PHY_ADDRESS, PHY_SR);
            if ((RegValue & PHY_DUPLEX_STATUS) != (uint16_t)RESET) {
                ETH_InitStructure.ETH_Mode = ETH_Mode_FullDuplex;
            } else {
                ETH_InitStructure.ETH_Mode = ETH_Mode_HalfDuplex;
            }
            if (RegValue & PHY_SPEED_STATUS) {
                /* Set Ethernet speed to 10M following the auto-negotiation */
                ETH_InitStructure.ETH_Speed = ETH_Speed_10M;
            } else {
                /* Set Ethernet speed to 100M following the auto-negotiation */
                ETH_InitStructure.ETH_Speed = ETH_Speed_100M;
            }
            /*------------ ETHERNET MACCR Re-Configuration -------------*/
            /* Get the ETHERNET MACCR value */
            tmpreg = ETH->MACCR;
            /* Set the FES bit according to ETH_Speed value */
            /* Set the DM bit according to ETH_Mode value */
            tmpreg |= (uint32_t)(ETH_InitStructure.ETH_Speed | ETH_InitStructure.ETH_Mode);
            /* Write to ETHERNET MACCR */
            ETH->MACCR = (uint32_t)tmpreg;
            Delay(1);
            tmpreg = ETH->MACCR;
            ETH->MACCR = tmpreg;
        }
        /* Restart MAC interface */
        ETH_Start();
#if LWIP_DHCP
        ipaddr.addr = 0;
        netmask.addr = 0;
        gw.addr = 0;
        g_lwip_dhcp_state = LWIP_DHCP_START;
#else
IP4_ADDR(&ipaddr,g_lwip_dhcp_struct.ip[0],g_lwip_dhcp_struct.ip[1],g_lwip_dhcp_struct.ip[2],g_lwip_dhcp_struct.ip[3]);
IP4_ADDR(&netmask,g_lwip_dhcp_struct.netmask[0],g_lwip_dhcp_struct.netmask[1] ,g_lwip_dhcp_struct.netmask[2],g_lwip_dhcp_struct.netmask[3]);
IP4_ADDR(&gw,g_lwip_dhcp_struct.gateway[0],g_lwip_dhcp_struct.gateway[1],g_lwip_dhcp_struct.gateway[2],g_lwip_dhcp_struct.gateway[3]);
#endif /* USE_DHCP */
        netif_set_addr(netif, &ipaddr , &netmask, &gw);
       /* When the netif is fully configured this function must be called.*/
        netif_set_up(netif);
    } 
        else 
        {
        ETH_Stop();
#if LWIP_DHCP
        g_lwip_dhcp_state = LWIP_DHCP_LINK_DOWN;
        dhcp_stop(netif);
#endif 
       /*  When the netif link is down this function must be called.*/
       netif_set_down(netif);
    }
}

/**
  * @brief  This function handles Ethernet link status.
  * @param  None
  * @retval None
  */
void Eth_Link_Status(struct netif *netif)
{
    uint32_t regvalue = 0;
    regvalue=ETH_ReadPHYRegister(LAN8720_PHY_ADDRESS, PHY_BSR);
    regvalue &= PHY_Linked_Status;
    /* Check whether the netif link down and the PHY link is up */
    if(!netif_is_link_up(netif) && (regvalue))
    {
      /* network cable is connected */
      netif_set_link_up(netif);
        if(eth_link_status==1)
        {
         eth_link_status=2;
         ETH_link_callback(netif);
        }
    }
    else if(netif_is_link_up(netif) && (!regvalue))
    {
      /* network cable is disconnected */
      netif_set_link_down(netif);
        g_lwip_dhcp_struct.canuse = 0;
        eth_link_status=1;
#if LWIP_DHCP
      /* Update DHCP state machine */
      g_lwip_dhcp_state = LWIP_DHCP_LINK_DOWN;
#endif /* LWIP_DHCP */
    }
}

/**
  * @breif    LWIP轮询任务
  */
void lwip_periodic_handle(void)
{
#if LWIP_TCP
    /* TCP periodic process every 250 ms */
    if (sys_now() - TCPTimer >= TCP_TMR_INTERVAL)
    {
    TCPTimer =  sys_now();
    tcp_tmr();
    }
#endif
    /* ARP periodic process every 5s */
    if ((sys_now() - ARPTimer) >= ARP_TMR_INTERVAL)
    {
    ARPTimer =  sys_now();
    etharp_tmr();
    }
#if LWIP_DHCP       /* 如果使用DHCP */
    /* Fine DHCP periodic process every 500ms */
    if (sys_now() - DHCPfineTimer >= DHCP_FINE_TIMER_MSECS)
    {
        DHCPfineTimer =  sys_now();
              dhcp_fine_tmr();
        /* process DHCP state machine */
              if ((g_lwip_dhcp_state != LWIP_DHCP_ADDRESS_ASSIGNED)&&
                     (g_lwip_dhcp_state != LWIP_DHCP_TIMEOUT)&&
                   (g_lwip_dhcp_state != LWIP_DHCP_LINK_DOWN))
        { 
           /* process DHCP state machine */
                     lwip_dhcp_process();
        }
    }
        /* DHCP Coarse periodic process every 60s */
        if (sys_now() - DHCPcoarseTimer >= DHCP_COARSE_TIMER_MSECS)
        {
                DHCPcoarseTimer =  sys_now();
                dhcp_coarse_tmr();
        }
#endif
      /* Check link status periodically */
        if ((sys_now() - LinkTimer) >= LINK_TIMER_INTERVAL) {
                Eth_Link_Status(&g_lwip_netif);
                LinkTimer=sys_now();
        }
}


#if LWIP_DHCP  /* 如果使用DHCP */
/**
 * @brief       lwIP的DHCP分配进程
 * @param       netif:网卡控制块
 * @retval      无
 */
void lwip_dhcp_process(void)
{
    uint32_t ip = 0;
    uint32_t netmask = 0;
    uint32_t gw = 0;
    struct dhcp *dhcp;
    switch (g_lwip_dhcp_state)//根据DHCP状态进入执行相应的动作
    {
        case LWIP_DHCP_START:{
        //对IP地址、网关地址及子网页码清零操作
        ip_addr_set_zero_ip4(&g_lwip_netif.ip_addr);
        ip_addr_set_zero_ip4(&g_lwip_netif.netmask);
        ip_addr_set_zero_ip4(&g_lwip_netif.gw);
        //设置DHCP的状态为等待分配IP地址
        g_lwip_dhcp_state = LWIP_DHCP_WAIT_ADDRESS;
        //开启DHCP
        dhcp_start(&g_lwip_netif);
        }break;
        case LWIP_DHCP_WAIT_ADDRESS:{
        ip = g_lwip_netif.ip_addr.addr;       //读取新IP地址
        netmask = g_lwip_netif.netmask.addr;  //读取子网掩码
        gw = g_lwip_netif.gw.addr;            //读取默认网关
        if (ip != 0)
        {
            g_lwip_dhcp_state = LWIP_DHCP_ADDRESS_ASSIGNED;
            /* Stop DHCP */
              dhcp_stop(&g_lwip_netif);
            g_lwip_dhcp_struct.canuse = 1;
            eth_link_status=0;
            //解析出通过DHCP获取到的IP地址 */
            g_lwip_dhcp_struct.ip[3] = (uint8_t)(ip >> 24);
            g_lwip_dhcp_struct.ip[2] = (uint8_t)(ip >> 16);
            g_lwip_dhcp_struct.ip[1] = (uint8_t)(ip >> 8);
            g_lwip_dhcp_struct.ip[0] = (uint8_t)(ip);
            printf("通过DHCP获取到IP地址......%d.%d.%d.%d\r\n", g_lwip_dhcp_struct.ip[0], g_lwip_dhcp_struct.ip[1], g_lwip_dhcp_struct.ip[2], g_lwip_dhcp_struct.ip[3]);
            //解析通过DHCP获取到的子网掩码地址
            g_lwip_dhcp_struct.netmask[3] = (uint8_t)(netmask >> 24);
            g_lwip_dhcp_struct.netmask[2] = (uint8_t)(netmask >> 16);
            g_lwip_dhcp_struct.netmask[1] = (uint8_t)(netmask >> 8);
            g_lwip_dhcp_struct.netmask[0] = (uint8_t)(netmask);
            printf("通过DHCP获取到子网掩码....%d.%d.%d.%d\r\n", g_lwip_dhcp_struct.netmask[0], g_lwip_dhcp_struct.netmask[1], g_lwip_dhcp_struct.netmask[2], g_lwip_dhcp_struct.netmask[3]);
            //解析出通过DHCP获取到的默认网关 
            g_lwip_dhcp_struct.gateway[3] = (uint8_t)(gw >> 24);
            g_lwip_dhcp_struct.gateway[2] = (uint8_t)(gw >> 16);
            g_lwip_dhcp_struct.gateway[1] = (uint8_t)(gw >> 8);
            g_lwip_dhcp_struct.gateway[0] = (uint8_t)(gw);
            printf("通过DHCP获取到的默认网关..%d.%d.%d.%d\r\n", g_lwip_dhcp_struct.gateway[0], g_lwip_dhcp_struct.gateway[1], g_lwip_dhcp_struct.gateway[2], g_lwip_dhcp_struct.gateway[3]);
            
            IP4_ADDR(&(g_lwip_netif.ip_addr), g_lwip_dhcp_struct.ip[0], g_lwip_dhcp_struct.ip[1], g_lwip_dhcp_struct.ip[2], g_lwip_dhcp_struct.ip[3]);
            IP4_ADDR(&(g_lwip_netif.netmask), g_lwip_dhcp_struct.netmask[0], g_lwip_dhcp_struct.netmask[1], g_lwip_dhcp_struct.netmask[2], g_lwip_dhcp_struct.netmask[3]);
            IP4_ADDR(&(g_lwip_netif.gw), g_lwip_dhcp_struct.gateway[0], g_lwip_dhcp_struct.gateway[1], g_lwip_dhcp_struct.gateway[2], g_lwip_dhcp_struct.gateway[3]);
            netif_set_addr(&g_lwip_netif, &g_lwip_netif.ip_addr, &g_lwip_netif.netmask, &g_lwip_netif.gw);
        }
        else
        {
            dhcp = (struct dhcp *)netif_get_client_data(&g_lwip_netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP);
            if(dhcp->tries > LWIP_MAX_DHCP_TRIES)//DHCP超时
            {
                g_lwip_dhcp_state = LWIP_DHCP_TIMEOUT;
                //停止DHCP
                dhcp_stop(&g_lwip_netif);
                g_lwip_dhcp_struct.canuse = 1;
                eth_link_status=0;
                //使用静态IP地址
                IP4_ADDR(&(g_lwip_netif.ip_addr), g_lwip_dhcp_struct.ip[0], g_lwip_dhcp_struct.ip[1], g_lwip_dhcp_struct.ip[2], g_lwip_dhcp_struct.ip[3]);
                IP4_ADDR(&(g_lwip_netif.netmask), g_lwip_dhcp_struct.netmask[0], g_lwip_dhcp_struct.netmask[1], g_lwip_dhcp_struct.netmask[2], g_lwip_dhcp_struct.netmask[3]);
                IP4_ADDR(&(g_lwip_netif.gw), g_lwip_dhcp_struct.gateway[0], g_lwip_dhcp_struct.gateway[1], g_lwip_dhcp_struct.gateway[2], g_lwip_dhcp_struct.gateway[3]);
                netif_set_addr(&g_lwip_netif, &g_lwip_netif.ip_addr, &g_lwip_netif.netmask, &g_lwip_netif.gw);
                printf("静态IP地址........%d.%d.%d.%d\r\n",g_lwip_dhcp_struct.ip[0],g_lwip_dhcp_struct.ip[1],g_lwip_dhcp_struct.ip[2],g_lwip_dhcp_struct.ip[3]);
                printf("子网掩码..........%d.%d.%d.%d\r\n",g_lwip_dhcp_struct.netmask[0],g_lwip_dhcp_struct.netmask[1],g_lwip_dhcp_struct.netmask[2],g_lwip_dhcp_struct.netmask[3]);
                printf("默认网关..........%d.%d.%d.%d\r\n",g_lwip_dhcp_struct.gateway[0],g_lwip_dhcp_struct.gateway[1],g_lwip_dhcp_struct.gateway[2],g_lwip_dhcp_struct.gateway[3]);
            }
        }
        }break;
        case LWIP_DHCP_LINK_DOWN:{
         dhcp_stop(&g_lwip_netif);//停止DHCP
         g_lwip_dhcp_state = LWIP_DHCP_OFF;
        }break;
        default: break;
   }
}
#endif

#ifndef __LWIPCONF_H
#define __LWIPCONF_H 

#include "stm32f4xx.h"

//DHCP进程状态
#define LWIP_DHCP_OFF                   (uint8_t) 0     //DHCP服务器关闭状态
#define LWIP_DHCP_START                 (uint8_t) 1     //DHCP服务器启动状态 
#define LWIP_DHCP_WAIT_ADDRESS          (uint8_t) 2     //DHCP服务器等待分配IP状态
#define LWIP_DHCP_ADDRESS_ASSIGNED      (uint8_t) 3     //DHCP服务器地址已分配状态
#define LWIP_DHCP_TIMEOUT               (uint8_t) 4     //DHCP服务器超时状态
#define LWIP_DHCP_LINK_DOWN             (uint8_t) 5     //DHCP服务器链接失败状态

#define LWIP_MAX_DHCP_TRIES        4   //DHCP服务器最大重试次数
   
//lwip控制结构体
typedef struct  
{
    uint8_t remoteip[4];       //远端主机IP地址 
    uint8_t ip[4];               //本机IP地址
    uint8_t netmask[4];        //子网掩码
    uint8_t gateway[4];        //默认网关的IP地址
  uint8_t canuse;

}Lwip_Dhcp_Struct;
extern Lwip_Dhcp_Struct g_lwip_dhcp_struct;    //lwip控制结构体

void lwip_pkt_handle(void);
void lwip_periodic_handle(void);
uint8_t LwIP_Init(void);
#endif

(2).stm32f4xx_it.c文件

/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_it.h"
#include "stm32f4x7_eth.h"
#include "usart1.h"
#include "tim2.h"
#include "lwipconf.h"
/** @addtogroup Template_Project
  * @{
  */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/******************************************************************************/
/*            Cortex-M4 Processor Exceptions Handlers                         */
/******************************************************************************/

/**
  * @brief  This function handles NMI exception.
  * @param  None
  * @retval None
  */
void NMI_Handler(void)
{
}

/**
  * @brief  This function handles Hard Fault exception.
  * @param  None
  * @retval None
  */
void HardFault_Handler(void)
{
  /* Go to infinite loop when Hard Fault exception occurs */
  while (1)
  {
  }
}

/**
  * @brief  This function handles Memory Manage exception.
  * @param  None
  * @retval None
  */
void MemManage_Handler(void)
{
  /* Go to infinite loop when Memory Manage exception occurs */
  while (1)
  {
  }
}

/**
  * @brief  This function handles Bus Fault exception.
  * @param  None
  * @retval None
  */
void BusFault_Handler(void)
{
  /* Go to infinite loop when Bus Fault exception occurs */
  while (1)
  {
  }
}

/**
  * @brief  This function handles Usage Fault exception.
  * @param  None
  * @retval None
  */
void UsageFault_Handler(void)
{
  /* Go to infinite loop when Usage Fault exception occurs */
  while (1)
  {
  }
}

/**
  * @brief  This function handles SVCall exception.
  * @param  None
  * @retval None
  */
void SVC_Handler(void)
{
}

/**
  * @brief  This function handles Debug Monitor exception.
  * @param  None
  * @retval None
  */
void DebugMon_Handler(void)
{
}

/**
  * @brief  This function handles PendSVC exception.
  * @param  None
  * @retval None
  */
void PendSV_Handler(void)
{
}

/**
  * @brief  This function handles SysTick Handler.
  * @param  None
  * @retval None
  */
void SysTick_Handler(void)
{

}


//串口1接受中断函数
void USART1_IRQHandler(void)
{    
    unsigned char ch;
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    {
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
        ch = USART_ReceiveData(USART1);
        Usart1_Callbcak(ch);
    }
}


//定时器2中断函数
void TIM2_IRQHandler(void)
{
    if( TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET ) 
    {
    TIM_ClearITPendingBit(TIM2, TIM_FLAG_Update);
    Tim2_Callback();
  }         
}


void ETH_IRQHandler(void)
{
  /* Handles all the received frames */
  if(ETH_CheckFrameReceived()) 
  {        
    lwip_pkt_handle();
  }
  /* Clear the Eth DMA Rx IT pending bits */
  ETH_DMAClearITPendingBit(ETH_DMA_IT_R);
  ETH_DMAClearITPendingBit(ETH_DMA_IT_NIS);
}


/******************************************************************************/
/*                 STM32F4xx Peripherals Interrupt Handlers                   */
/*  Add here the Interrupt Handler for the used peripheral(s) (PPP), for the  */
/*  available peripheral interrupt handler's name please refer to the startup */
/*  file (startup_stm32f4xx.s).                                               */
/******************************************************************************/

/**
  * @brief  This function handles PPP interrupt request.
  * @param  None
  * @retval None
  */
/*void PPP_IRQHandler(void)
{
}*/

/**
  * @}
  */ 

(3).main.c文件

/**
  ******************************************************************************
  * @file    Project/STM32F4xx_StdPeriph_Templates/main.c 
  * @author  MCD Application Team
  * @version V1.8.1
  * @date    27-January-2022
  * @brief   Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2016 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include <stdio.h>
#include "mtnvic.h"
#include "usart1.h"
#include "arm_math.h"
#include "lwipconf.h"
#include "tim2.h"
#include "mtdelay.h"
#include "mtnvic.h"
/** @addtogroup Template_Project
  * @{
  */ 

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/

char mainusart1recv[5]={0};
/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/
/**
  * @brief  Main program
  * @param  None
  * @retval None
  */
int main(void)
{
	MT_NVIC_Init();
  Usart1_Init(115200);
	Tim2_Init();
	LwIP_Init();
  /* Infinite loop */
  while (1)
  {
		lwip_periodic_handle();
  }
}





#ifdef  USE_FULL_ASSERT

/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{ 
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
}
#endif

/**
  * @}
  */


7.参考链接

STM32F407【标准库】+LAN8720A+FreeRTOS移植LwIP(2.1.3)→实现DHCP_stsw-stm32070-CSDN博客

六、STM32F4+标准库+LWIP2.1.2移植+无操作系统_stm32|lwip2.1.2移植-CSDN博客

43. ETH—Lwip以太网通信 — [野火]STM32库开发实战指南——基于野火霸天虎开发板 文档

在此感谢链接的作者们。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2047734.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【TM1638不能成功读回按键值】

8led8按键8数码管。主函数调用TM1638_ReadData2&#xff0c;打印了返回值&#xff0c;无论是否按键&#xff0c;都一直打印255&#xff0c;为什么全是1&#xff0c;看来读数据函数有问题啊。 u8 TM1638_ReadData2(void) {uint8_t i;uint8_t temp0x00;TM1638_DIOModeInput();/…

前端读取response.headers异常:Cannot read properties of undefined (reading ‘split‘)

[TOC](前端读取response.headers异常:Cannot read properties of undefined (reading ‘split’) ) 前端读取response.headers异常 Cannot read properties of undefined (reading ‘split’) TypeError: Cannot read properties of undefined (reading ‘split’) 报错解释&a…

如何修改计算机ip地址?几招教你轻松改

在日常使用计算机的过程中&#xff0c;有时我们需要修改计算机的IP地址&#xff0c;无论是出于网络安全、网络管理还是其他特定需求。然而&#xff0c;对于非专业人士来说&#xff0c;这一过程可能显得复杂且充满挑战。但别担心&#xff0c;本文将带您了解IP地址基础知识&#…

day04 --js的常用对象、BOM对象和DOM对象

一、常用对象 1.1 数组 1.创建数组:let arr [1,2,3]; let arr new Array(1,2,3);注意&#xff1a;JS数组不区分数据类型&#xff0c;而且其长度可以随意改变&#xff0c;因此JS数组类似于Java中的集合 ​ 2.数组常用方法:length:这是一个属性&#xff0c;用于获取数组长度fo…

以「垂直模型」引领AIGC商业化落地,FancyTech的技术路径是什么?

我们正在见证又一轮技术革新&#xff0c;这一次是 AIGC 为个体提供表达自我的工具&#xff0c;让创作变得更加容易和普及&#xff0c;但背后的推动力却并不是「大」模型。 点击访问我的技术博客https://ai.weoknow.comhttps://ai.weoknow.com 两年以来&#xff0c;AIGC 技术的发…

快速备份与检索ChatGPT对话记录,以及便捷关闭聊天历史教程

近期&#xff0c;ChatGPT 用户遭遇了一系列对话记录意外丢失的事件&#xff0c;引发了广泛的关注和不便。用户们对于重要聊天记录的安全性表示担忧&#xff0c;害怕珍贵的交流内容会不翼而飞。 令人欣慰的是&#xff0c;OpenAI 在2023年4月11日宣布推出了一项新的功能——Chat…

雨云美国二区E5v2服务器测评(非广告)

注&#xff1a;本文非广告&#xff0c;非推广 本文长期更新地址&#xff1a; 雨云美国二区E5v2服务器测评&#xff08;非广告&#xff09;-星零岁的博客https://blog.0xwl.com/13594.html 今天来测评一下雨云美国二区v2服务器。我测试的这台配置是4-8&#xff0c; 35 M上传&a…

SpringBoot教程(二十三) | SpringBoot实现分布式定时任务之xxl-job

SpringBoot教程&#xff08;二十三&#xff09; | SpringBoot实现分布式定时任务之xxl-job 简介一、前置条件&#xff1a;需要搭建调度中心1、先下载调度中心源码2、修改配置文件3、启动项目4、进行访问5、打包部署&#xff08;上正式&#xff09; 二、SpringBoot集成Xxl-Job1.…

水利机械5G智能制造工厂物联数字孪生平台,推进制造业数字化转型

在当今这个科技日新月异的时代&#xff0c;水利机械行业正经历着一场深刻的变革&#xff0c;其中5G智能制造工厂物联数字孪生平台的引入&#xff0c;无疑是推动制造业数字化转型的重要驱动力。工业物联数字孪生平台是智能制造工厂的核心组成部分&#xff0c;它基于物理世界的真…

入门mysql 数据库

mysql是关系型数据库 &#xff08;安装教程请参考主页相关文章https://blog.csdn.net/2401_86120676/article/details/141265678?spm1001.2014.3001.5502 和mysql Ubuntu安装与远程连接配置-CSDN博客&#xff09; mysql相关指令 1.数据库 展示所有的数据库&#xff1a;sho…

基于神经网络逆同步控制方法的两变频调速电机控制系统matlab仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 神经网络a阶逆系统 4.2 两电机的数学模型 4.3 两电机系统的神经网络逆同步控制 5.完整工程文件 1.课题概述 两电机变频调速系统是一个多输入多输出非线性强耦合的控制系统。本课题使用神经网络构造…

英伟达玩转剪枝、蒸馏:把Llama 3.1 8B参数减半,性能同尺寸更强

小模型崛起了。 上个月&#xff0c;Meta 发布了 Llama 3.1 系列模型&#xff0c;其中包括 Meta 迄今为止最大的 405B 模型&#xff0c;以及两个较小的模型&#xff0c;参数量分别为 700 亿和 80 亿。 Llama 3.1 被认为是引领了开源新时代。然而&#xff0c;新一代的模型虽然性能…

(javaweb)SpringBootWeb案例(毕业设计)案例--文件上传

1.简介 前端程序和服务端程序 对于前端 html文件放在static目录下 location---文件提交的位置 右键--copy value -------------c盘目录下 2.本地上传--文件存储 1. 2. 使用uuid&#xff1a;保证文件名是唯一的 此时 并没有文件的拓展名--所以需要---写后缀 用字符串截取 此时图…

Java、python、php版的宠物美容预约服务系统的设计与实现 (源码、调试、LW、开题、PPT)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人 八年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等&#xff0c;大家有这一块的问题可以一起交流&…

【报告】从 YCombinator 支持的 400 家(2023年和2024年) AI 初创公司看AI行业

这份报告对 YC 2023 年和 2024 年队列中的 417 家人工智能公司进行了广泛的分析。对于那些不知道的人来说&#xff0c;YCombinator是一个领先的初创企业加速器&#xff0c;提供种子资金、指导和资源&#xff0c;以帮助早期初创企业取得成功&#xff0c;YCombinator (YC)在发现和…

SOMEIP_ETS_044: echoUTF16DYNAMIC_with_odd_number_after_termination

测试目的&#xff1a; 验证设备&#xff08;DUT&#xff09;是否能够正确处理一个在终止符之后多出一个字节的echoUTF16DYNAMIC字符串&#xff0c;并且能够去除这个多余的字节。 描述 本测试用例旨在检查DUT在接收到一个不符合UTF16DYNAMIC字符串规范&#xff08;即在终止符…

【Python机器学习】利用PCA来简化数据——PCA

PCA&#xff08;主成分分析&#xff09;的优缺点&#xff1a; 优点&#xff1a;降低数据的复杂性&#xff0c;识别最重要的多个特征&#xff1b; 缺点&#xff1a;不一定需要&#xff0c;且可能损失有用信息&#xff1b; 适用数据类型&#xff1a;数值型数据。 移动坐标轴 如下…

【研发日记】嵌入式处理器技能解锁(四)——TI C2000 DSP的Memory

文章目录 前言 背景介绍 Memory映射 RAM ROM 外设Register Memory分配 应用实例 总结 参考资料 前言 见《【研发日记】嵌入式处理器技能解锁(一)——多任务异步执行调度的三种方法》 见《【研发日记】嵌入式处理器技能解锁(二)——TI C2000 DSP的SCI(串口)通信》 见《…

在线excel/csv转json数据

具体请访问&#xff1a;在线Csv/Excel(xls/xlsx)转Json格式工具

编程语言进化史

编程语言多到你想象不到。 图片来自: 程序设计语言概念 发展历史 自从1946年冯诺依曼原理被提出&#xff0c;计算机数据和指令是通过二进制形式以及后来的汇编语言(二进制助记符)&#xff0c;但依然没有改变容易出错的本质。1951年Rutishauser提出的用编译程序实现高级语言的思…