本章实现了基于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. 6.4 Windows驱动开发:内核枚举DpcTimer定时器

    在操作系统内核中,DPC(Deferred Procedure Call)是一种延迟执行的过程调用机制,用于在中断服务例程(ISR)的上下文之外执行一些工作.DPC定时器是基于DPC机制的一种定时执行 ...

  2. 2.4 Windows驱动开发:内核字符串拷贝与比较

    在上一篇文章<内核字符串转换方法>中简单介绍了内核是如何使用字符串以及字符串之间的转换方法,本章将继续探索字符串的拷贝与比较,与应用层不同内核字符串拷贝与比较也需要使用内核专用的API函数 ...

  3. 8.1 C++ 标准输入输出流

    C/C++语言是一种通用的编程语言,具有高效.灵活和可移植等特点.C语言主要用于系统编程,如操作系统.编译器.数据库等:C语言是C语言的扩展,增加了面向对象编程的特性,适用于大型软件系统.图形用户界面 ...

  4. workman在线五子棋

    一.下载安装workman,地址:https://github.com/walkor/workerman composer require workerman/workerman 二.cd到worke ...

  5. 树莓派4B改造成云桌面客户端,连接DoraCloud免费版

    Raspberry Pi(树莓派) 是为学习计算机编程教育而设计的只有信用卡大小的微型电脑,自问世以来受众多计算机发烧友和创客的追捧,曾经一"派"难求. DoraCloud是一款多 ...

  6. Label的背景色

    Label的背景色是 color属性,但是这个属性是 必须 Transparent 为 false的时候 才生效,否则不生效

  7. [JVM]逃逸分析

    逃逸分析 JVM的内存分配策略 首先回顾一下JVM的内存分配策略. JVM的内存包括方法区.堆.虚拟机栈.本地方法栈.程序计数器.一般情况下JVM运行时的数据都是存在栈和堆上的.栈用来存放一些基本变量 ...

  8. 推荐一款id生成器: Hashids

    唯一 id 生成的方式有很多种,比较常见的有以下几种方式: 语言自带功能,如 Java 中的 UUID,常用于后端 第三方工具提供,如 npm 中的 nanoid,常用于前端 Twitter 开源的 ...

  9. Python xpath语法与 lxml 模块

    XPath 语法 XPath 使用路径表达式来选取 XML 文档中的节点或节点集.节点是通过沿着路径 (path) 或者步 (steps) 来选取的. XML 实例文档 我们将在下面的例子中使用这个 ...

  10. 从零开始的微信小程序入门教程(二),初识WXML与WXSS

    壹 ❀ 引 时隔大半年,我终于开始写小程序入门教程的第二篇了,其实我也在纳闷,这么久的时间我到底干了什么,仔细一想,我学了JavaScript部分进阶知识,学了ES6,系统性的去复习了angularj ...