本章实现了基于STM32F407MAC的数据收发功能,通过开发板的RJ45接口连接网线到电脑,电脑使用Wiershark工具抓包验证,工程源码、资料和软件见文末

参考文档:

DP83848IV英文

DP83848EP中文

STM32F4xx参考手册

抓包工具:wireshark

一、工程模板以及参考源码的获取

工程源码我使用的正点原子的探索者开发板STM32F407(V2)参考源码:正点原子文档中心

参考源码使用的是STM官方的F407移植LwIP的例程-STSW-STM32070,这个例程主要是STM32移植LwIP实现TP/IP通讯的,我们只需要参考里面关于MAC配置部分代码即可。

移植的话只需要将所有的dp83848.c和dp83848.h的代码复制将文件添加到工程,添加相关的头文件,工程中添加ETH驱动库文件,裸机移植把main.c中task2放到主循环就可以了。

工程源码和参考文件在文末。

二、开发板STM32以及DP83848 PHY的硬件配置

开发板的单片机使用的是STM32F407ZGT6,与原子的例程一致就不需要修改了,开发板的DP83848硬件连接如下,完整原理图放在文末。

主要的连接就是与单片机连接的RMII接口和连接网线的RJ45接口,其他的外部配置可以参考上一章或者DP83848的手册。DP83848IV与DP83848EP只是性能不同,但是硬软件配置是一样的。

三、软件配置

在准备好开发板以及工程源码后就可以开始配置工程和写相关代码了。

3.1、添加STM32F4x7_ETH驱动库文件到工程

STM32F4xx的固件库是没有ETH驱动的,STM32F4x7_ETH驱动库文件在我们下载的STSW-STM32070的STM32F4x7_ETH_LwIP_V1.1.0-Libraries-STM32F4x7_ETH_Driver,这个里面是ETH驱动的头文件和源码,注意stm32f4x7_eth_conf_template.h文件是PHY的接口示例文件,使用不同的PHY就需要修改里面的配置,主要为不同PHY的部分寄存器地址不同,需要将文件名修改为stm32f4x7_eth_conf.h直接拿来使用。官方例程使用的也是DP83848,因此不需要修改。

ETH外设需要用到延时函数,通过定义 USE_Delay可以使用我们自定的延时,比如原子例程提供的delay.c中的系统定时器延时,注释掉#define USE_Delay的话就是用ETH驱动库自带的简单延时。

新建dp83848.c和dp83848.h文件并添加到工程,添加过程就不赘述了。

添加好文件的工程如下(注意需要将.h文件的路径添加到工程)

3.2、PYH接口(RMII、SMI)的配置(dp83848.c)

文件添加好之后接下来就是硬件接口的配置了,STM32的RMII、SMI接口配置如下

/* Private function prototypes -----------------------------------------------*/
static void ETH_GPIO_Config(void);
/**
 * @brief Configures the different GPIO ports.
* @param None
* @retval None
*/
void ETH_GPIO_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
/*Enable GPIO clocks*/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA |
RCC_AHB1Periph_GPIOC |
RCC_AHB1Periph_GPIOG, ENABLE);
/*Enable SYSCFG clock*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
  /*DP83848 使用单独的外部晶振,不使用STM32提供时钟源*/
#ifdef PHY_CLOCK_MCO
  /* Configure MCO (PA8) */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  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);
#endif
/* MII/RMII Media interface selection --------------------------------------*/
  SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_RMII);
/* Ethernet pins configuration ************************************************/
/*网络引脚设置 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*/
  //配置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);
}

主要就是配置RMII、SMI接口的时钟、引脚复用、引脚模式、引脚翻转速率、上下拉模式,对于PHY_CLOCK_MCO的PA8接口,DP83848直接使用外部50MHz晶振(原理图的Y3),所以不需要配置(不定义宏PHY_CLOCK_MCO)。

3.3、配置ETH_MACDMA以太网接口(dp83848.c)

/* Private function prototypes -----------------------------------------------*/
static void ETH_MACDMA_Config(void);

/**
 * @brief Configures the Ethernet Interface
 * @param None
 * @retval None
 */
static void ETH_MACDMA_Config(void)
{
  ETH_InitTypeDef ETH_InitStructure;
  /* 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_10M;
  // 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 */
  ETH_Init(&ETH_InitStructure, DP83848_PHY_ADDRESS);
  /* Enable the Ethernet Rx Interrupt */
  ETH_DMAITConfig(ETH_DMA_IT_NIS | ETH_DMA_IT_R, ENABLE);
}

以上函数参考了官方代码stm32f4x7_eth_bsp.c中的 static void ETH_MACDMA_Config(void)函数代码。

首先初始化ETH相关时钟的时钟,然后ETH_DeInit()复位ETH外设寄存器的值、ETH外设软件复位,复位完成后就可以配置ETH结构体了。

/* Call ETH_StructInit if you don't like to configure all ETH_InitStructure parameter */
ETH_StructInit(&ETH_InitStructure);

以上直接配置了ETH的默认值,然后可以根据需要配置需要修改的结构体成员,结构体成员比较多,具体的信息可以查看STM32F4xx手册ETH章节的寄存器说明。

/* Configure Ethernet */
ETH_Init(&ETH_InitStructure, DP83848_PHY_ADDRESS);

之后就是初始化PHY了。在默认情况下DP83848的配置地址为0x01,这是由DP83848的硬件配置决定的,开发板没有进行额外配置,因此PHY地址为0x01,地址宏定义在dp83848.h。如果需要配置PHY地址可以参考第二章的第三节配置或者DP83848参考手册。

/* Enable the Ethernet Rx Interrupt */
ETH_DMAITConfig(ETH_DMA_IT_NIS | ETH_DMA_IT_R, ENABLE);

最后使能了ETH的输入。

3.4、配置ETH中断和中断处理函数(dp83848.c)

/* Private function prototypes -----------------------------------------------*/
static void ETH_NVIC_Config(void);
/**
* @brief Configures and enable the Ethernet global interrupt.
* @param None
* @retval None
*/
void ETH_NVIC_Config(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  /* Enable the Ethernet global Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = ETH_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}
/**
* @brief This function handles ethernet DMA interrupt request.
* @param None
* @retval None
*/
void ETH_IRQHandler(void)
{
  /* Handles all the received frames */
  /* check if any packet received */
  while(ETH_CheckFrameReceived()){
  /* process received ethernet packet */
  Pkt_Handle();
}
  /* Clear the Eth DMA Rx IT pending bits */
  ETH_DMAClearITPendingBit(ETH_DMA_IT_R);
  ETH_DMAClearITPendingBit(ETH_DMA_IT_NIS);
}

以上为ETH的接收中断配置中断函数stm32f4x7_eth_bsp.c中配置的分组为1子优先级为0,优先级低于系统定时器,当接收到数据包时就会触发中断。

/* check if any packet received */
while(ETH_CheckFrameReceived()){
/* process received ethernet packet */
  Pkt_Handle();
}

ETH_CheckFrameReceived()会检查是否接收到数据包,如果接收到数据包则会调用Pke_Handle()回调函数。

在处理完后,调用ETH_DMAClearITPendingBit()将相关的中断标志清除,等待下一次触发中断。

在官方例程中,ETH_IRQHandler(void)中则是使用信号量唤醒LwIP任务,之后的LwIP移植也是这样实现。

3.5、中断回调函数Pkt_Handle()(dp83848.c)

/* Private function prototypes -----------------------------------------------*/
void Pkt_Handle(void);

/** 
 * @brief  Configures the Ethernet Interface 
 * @param  None 
 * @retval None 
 */
void Pkt_Handle(void)
{
  struct pbuf *p= NULL, *q;
  uint32_t receiveLen;
  FrameTypeDef frame;
  u8 *receiveBuffer;
  __IO ETH_DMADESCTypeDef *DMARxNextDesc;
  uint32_t i=0;
  /* get received frame */
  frame = ETH_Get_Received_Frame();
  /* Obtain the size of the packet and put it into the "len" variable. */
  receiveLen = frame.length;
  receiveBuffer = (u8 *)frame.buffer;
  printf("0011%d0022\n", receiveLen); //将每一个的包长度发往串口
  if(receiveBuffer[41] == 10){
      /*如果第42字节是十进制10,则将整个包内容发往串口*/
      for (i = 0; i < receiveLen; i++){
        printf("%c", receiveBuffer[i]);
      }
  }
  /* Check if frame with multiple DMA buffer segments */
  if (DMA_RX_FRAME_infos->Seg_Count > 1) {
    DMARxNextDesc = DMA_RX_FRAME_infos->FS_Rx_Desc;
    }else{
    DMARxNextDesc = frame.descriptor;
    }
  /* Release descriptors to DMA */
  //DMARxNextDesc = frame.descriptor;   /* Set Own bit in Rx descriptors: gives the buffers back to DMA */
  for (i = 0; i < DMA_RX_FRAME_infos->Seg_Count; i++) {
    DMARxNextDesc->Status = ETH_DMARxDesc_OWN;
    DMARxNextDesc = (ETH_DMADESCTypeDef *)(DMARxNextDesc->Buffer2NextDescAddr);
  }   /* Clear Segment_Count */
  DMA_RX_FRAME_infos->Seg_Count = 0;   /* When Rx Buffer unavailable flag is set: clear it and resume reception */
  if ((ETH->DMASR & ETH_DMASR_RBUS) != (u32)RESET) {
    /* Clear RBUS ETHERNET DMA flag */
    ETH->DMASR = ETH_DMASR_RBUS;
    /* Resume DMA reception */
    ETH->DMARPDR = 0;
  }
}

函数Pkt_Handle(void) 参考了官方例程中Utilities/Third_Party_lwip-1.4.1中的ethernetif.c文件中的low_level_input()函数,这个是官方例程的接收数据包函数,我们修改一下只需要将受到的数据包的大小以及数据发送到串口。

ETH_Get_Received_Frame()

用于获取网络数据包,获取数据包有两个函数分别为ETH_Get_Received_Frame(void)和ETH_Get_Received_Frame_interrupt(void),前者用于轮询接收后者用于中断接收。

  /* Obtain the size of the packet and put it into the "len" variable. */
  receiveLen = frame.length;
  receiveBuffer = (u8 *)frame.buffer;
  printf("0011%d0022\n", receiveLen); //将每一个的包长度发往串口
  if(receiveBuffer[41] == 10){
      /*如果第42字节是十进制10,则将整个包内容发往串口*/
      for (i = 0; i < receiveLen; i++){
        printf("%c", receiveBuffer[i]);
      }
  }

接下来就是获取数据包的长度receiveLen与数据receiveBuffer,通过串口打印出来。通过检测数据包的第42个字节为10,然后将收到的帧打印,我们使用 ping 192.168.2.10(只要是xxx.xxx.x.10就行)的第42个字节就是10。

  /* Check if frame with multiple DMA buffer segments */
  if (DMA_RX_FRAME_infos->Seg_Count > 1) {
    DMARxNextDesc = DMA_RX_FRAME_infos->FS_Rx_Desc;
    }else{
    DMARxNextDesc = frame.descriptor;
    }

已经完成了这一帧数据的操作,需要将帧状态的分段计数Seg_Count减小到1,再向DMA释放描述符。

3.6、ETH发送函数(dp83848.c)

/* Global pointers to track current transmit and receive descriptors */
extern ETH_DMADESCTypeDef *DMATxDescToSet;
extern ETH_DMADESCTypeDef *DMARxDescToGet;
/**
* @brief ETH_BSP_Config
* @param Data、Length
* @retval None
*/
void DP83848Send(u8* data, u16 length){
  memcpy((u8 *)DMATxDescToSet->Buffer1Addr, data, length);
  /* Prepare transmit descriptors to give to DMA*/
  ETH_Prepare_Transmit_Descriptors(length);
}

ETH发送函数参考了官方例程中Utilities/Third_Party_lwip-1.4.1中的ethernetif.c中的low_level_output()函数,这里直接将data的指针的数据复制到当前发送描述符数据地址Addr1中,直接使用ETH_Prepare_Transmit_Descriptors();发送数据。

3.7、ETH_DMA初始化(dp83848.c)

#include "DP83848.h"
#include "stm32f4x7_eth.h"
#include <string.h>
#include <stdio.h> /* Ethernet Rx & Tx DMA Descriptors */
extern ETH_DMADESCTypeDef DMARxDscrTab[ETH_RXBUFNB], DMATxDscrTab[ETH_TXBUFNB];
/* Ethernet Receive buffers */
extern uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE];
/* Ethernet Transmit buffers */
extern uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE]; void DP83848Init(uint8_t* HWADDR){
int i;
/* Configure ethernet (GPIOs, clocks, MAC, DMA) */
  ETH_BSP_Config();
/* initialize MAC address in ethernet MAC */
  ETH_MACAddressConfig(ETH_MAC_Address0, HWADDR);
/* Initialize Tx Descriptors list: Chain Mode */
  ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
/* Initialize Rx Descriptors list: Chain Mode */
  ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
/* Enable the TCP, UDP and ICMP checksum insertion for the Tx frames */
  for(i = 0; i < ETH_TXBUFNB; i++) {
ETH_DMATxDescChecksumInsertionConfig(&DMATxDscrTab[i], ETH_DMATxDesc_ChecksumTCPUDPICMPFull);
  }
  ETH_Start();
}

ETH初始化函数参考了官方例程中Utilities/Third_Party_lwip-1.4.1中的ethernetif.c中的low_level_init()函数,ETH_BSP_Config()初始化了相关配置,ETH_MACAddressConfig()初始化MAC地址,ETH_DMATxDescChainInit()和ETH_DMARxDescChainInit()创建了两个链状描述符,FIFO最大只有2KB,因此FIFO设定的最大阈值不会超过2KB(具体值参考STM32F4x手册),当单个帧大于FIFO设定阈值时,单个描述符描述不了一个帧,大于的数据的地址将会存入下一个描述符,以此类推。
描述符两种结构可以参考STMF4xx官方手册的29.6节:以太网功能说明:DMA 控制器操作
官方手册的帧发送处理帧接收处理两小节提到了描述符再数据处理过程的作用

描述符可参考:以太网DMA描述符

3.8、硬件初始化ETH_BSP_Config(void)

/**
 * @brief ETH_BSP_Config
* @param None
* @retval None
*/
void ETH_BSP_Config(void)
{
ETH_GPIO_Config(); ETH_MACDMA_Config(); ETH_NVIC_Config();
}

3.8、DP83848.h文件

#ifndef __DP83848_H
#define __DP83848_H
#include "sys.h"
/* Exported constants --------------------------------------------------------*/
#define DP83848_PHY_ADDRESS 0x01
/* Exported functions ------------------------------------------------------- */
void DP83848Init(uint8_t* HWADDR);
void DP83848Send(u8* data, u16 length);
#endif /* __DP83848_H */

dp83848.h 写了PHY地址,以及DP83848初始化函数和发送函数供外部调用。

3.9、main.c文件

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
#include "stm32f4x7_eth.h"
#include "DP83848.h" u8 mydata[60] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x08, 0x06, 0x00, 0x01,
0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0xc0, 0xa8, 0x02, 0xf0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8,
0x02, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; int main(void)
{
u8 MyMacAddr[6] = {0x08, 0x00, 0x06, 0x00, 0x00, 0x09};
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 中断分组配置
delay_init(168); // 初始化延时函数
uart_init();    // 初始化串口
LED_Init(); // 初始化LED端口
DP83848Init(MyMacAddr);
printf("test");
while (1)
{
DP83848Send(mydata, 60);
LED0 = !LED0;
delay_ms(1000);
}
}

周期性的发送mydata ARP数据包再上位机能够被监听到,接收处理函数则在中断回调函数中。

四、测试

在烧录完程序之后将开发板的串口和以太网连接置电脑,打卡串口助手和Wireshark。

Wireshark能够监听到开发板每隔一秒发送的ARP数据包,与我们定义的mydata中的数据是一致的。

电脑打开CMD,ping一个网络地址192.168.2.10,开发板接收到数据包的42位为10,串口将接收到的数据包打印出来。

抓包工具也能看到ping 192.168.2.10发送的ARP数据包。

参考资料和软件:

链接:https://pan.baidu.com/s/15diAYfW40L60S8iallRu_g?pwd=cc2r
提取码:cc2r

基于STM32F407MAC与DP83848实现以太网通讯三(STM32F407MAC配置以及数据收发)的更多相关文章

  1. 十几万条数据的表中,基于帝国cms 。自己亲身体验三种批量更新数据的方法,每一种的速度是什么样的

    需求是 上传Excel 读取里面的数据.根据Excel中某一个字段,与数据表中的一个字段的唯一性.然后把 Excel表中数据和数据库表中数据一次更改.本次测试一次更新31条数据. 本次测试基于帝国cm ...

  2. 基于CC2530的ZigBee转以太网网关的设计与实现

    *已刊登至:<无线电>8月刊 物联网技术的实现中,无线技术是必不可少的部分. 近年无线技术的发展,将ZigBee推入人们的视线中.那么ZigBee是如何的一种技术呢?带着疑问.我查询了它的 ...

  3. STM32F412应用开发笔记之五:结合W5500实现以太网通讯

    因实际使用需求我们测试一下网络通讯,在NUCLEO-F412ZG测试板上没有以太网部分,我们选择外接一个W5500的实验板.W5500支持SPI接口通讯,DC3.3V供源.而NUCLEO-F412ZG ...

  4. 基于dubbo框架下的RPC通讯协议性能测试

    一.前言 Dubbo RPC服务框架支持丰富的传输协议.序列化方式等通讯相关的配置和扩展.dubbo执行一次RPC请求的过程大致如下:消费者(Consumer)向注册中心(Registry)执行RPC ...

  5. [iOS 基于CoreBluetooth的蓝牙4.0通讯]

    一.首先大致介绍下蓝牙4.0的模式,中心和周边: 一般情况下,iPhone作为中心,接收来自周边传感器(比如手环等)采集的数据. 二.那整一个数据通讯的协议是怎样的呢? 为什么要一层层搞这么复杂呢?据 ...

  6. ACE框架 基于共享内存的进程间通讯

    ACE框架将基于共享内存的进程间通讯功能,如其它IO组件或IPC组件一样,设计成三个组件.流操作组件ACE_MEM_Stream,连接器组件ACE_MEM_Connector,以及接收连接组件ACE_ ...

  7. 西门子S7系列以太网通讯处理器功能介绍

    北京华科远创科技有限研发的远创智控型号ETH-YC模块适用于西门子S7-200/S7-300/S7-400.SMART S7-200.西门子数控840D.840DSL.合信.亿维PLC的PPI/MPI ...

  8. 西门子S7200/300/400以太网通讯处理器选型分类

    北京华科远创科技有限研发的远创智控转以太网模块适用于西门子S7-200/S7-300/S7-400.SMART S7-200.西门子数控840D.840DSL.合信.亿维PLC的PPI/MPI/PRO ...

  9. 常用 Gulp 插件汇总 —— 基于 Gulp 的前端集成解决方案(三)

    前两篇文章讨论了 Gulp 的安装部署及基本概念,借助于 Gulp 强大的 插件生态 可以完成很多常见的和不常见的任务.本文主要汇总常用的 Gulp 插件及其基本使用,需要读者对 Gulp 有一个基本 ...

  10. 基于Spark1.3.0的Spark sql三个核心部分

    基于Spark1.3.0的Spark sql三个核心部分: 1.可以架子啊各种结构化数据源(JSON,Hive,and Parquet) 2.可以让你通过SQL,saprk内部程序或者外部攻击,通过标 ...

随机推荐

  1. 月薪10K码农,跳槽到40K架构师,技术学习路线图汇总

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.介绍 Hey there! Roadmap to becoming a web devel ...

  2. SpringBoot分布式任务中间件开发 附视频讲解 (手把手教你开发和使用中间件)

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 分布式任务DcsSchedule中间件,Github地址:https://github.com ...

  3. scrapy抓取校花网图片

    一:基础版(抓取首页图片) 爬虫py文件代码: 1 # -*- coding: utf-8 -*- 2 import scrapy 3 import sys 4 import io 5 from sc ...

  4. 在Windows下编译Saba

      今天写一篇环境配置的博客,感觉这种博客比较好写   Saba是一个用于加载MMD(MikuMikuDance)模型.动作文件的C++库.下面我们在Windows下编译这个库.为了在Windows下 ...

  5. 扒开源安卓性能测试工具moblieperf源码——开发属于你自己的性能稳定性测试工具

    moblieperf下载和使用 moblieperf由阿里巴巴开源的Android性能测试工具 下载:官方源码地址mobileperf github 使用: 使用pycharm打开下载的项目 使用只需 ...

  6. MYSQL 3 DAY

    目录 MySQL day03 1.约束 1.1.唯一性约束(unique) 1.2.主键约束 1.3.外键约束 2.存储引擎?(整个内容属于了解内容) 2.1.完整的建表语句 2.2.什么是存储引擎呢 ...

  7. NC16466 [NOIP2015]信息传递

    题目链接 题目 题目描述 有 n 个同学(编号为 1 到 n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为 i 的同学的信息传递对象是编号为Ti的同学. 游戏开始时, ...

  8. Python list 中删除元素的方法

    在python列表中删除元素主要分为以下3种场景: 根据目标元素所在的索引位置进行删除,可以使用del关键字或pop()方法:根据元素本身的值进行删除,可使用列表(list类型)提供的remove() ...

  9. Linux查看系统版本的方法

    记录几种查看当前Linux系统的版本的方法 一.使用命令:cat /proc/version 查看 linux版本号:Linux version 5.4.0-99-generic (buildd@lg ...

  10. HTTP协议发展历程

    HTTP协议发展历程 HTTP超文本传输协议是一个用于传输超文本文档的应用层协议,它是为Web浏览器与Web服务器之间的通信而设计的,HTTP协议到目前为止全部的版本可以分为HTTP 0.9.HTTP ...