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(Ð_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(Ð_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Ð_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Ð_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,ðernetif_init,ðernet_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库开发实战指南——基于野火霸天虎开发板 文档
在此感谢链接的作者们。