首页 > 其他分享 >基于STM32F407MAC与DP83848实现以太网通讯三(STM32F407MAC配置以及数据收发)

基于STM32F407MAC与DP83848实现以太网通讯三(STM32F407MAC配置以及数据收发)

时间:2024-02-23 18:55:22浏览次数:23  
标签:DMA void 0x00 STM32F407MAC InitStructure DP83848 GPIO ETH 以太网

本章实现了基于STM32F407MAC的数据收发功能,通过开发板的RJ45接口连接网线到电脑,电脑使用Wiershark工具抓包验证。

参考文档:

DP83848IV英文

DP83848EP中文

STM32F4xx参考手册

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

工程源码我使用的正点原子的探索者开发板STM32F407(V2)参考源码:正点原子文档中心,在网盘文件中的工程源码->扩展例程->FreeRTOS例程->FreeRTOS实验6-1 FreeRTOS任务创建和删除实验(动态方法),这个实验直接使用裸机也没有问题,不过后面移植LwIP协议栈时就需要使用操作系统了。

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

二、开发板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可以使用我们自定的延时,比如原子例程提供的sys.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接口配置为复用,对于MDC的PA8接口,DP83848直接使用外部50MHz晶振(原理图的Y3),所以不需要配置。 

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的默认值,然后可以根据需要配置需要修改的结构体成员。

/* 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中断和中断处理函数

/* 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()

/* 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] == 201){       /*如果第42字节是十进制201,则将整个包内容发往串口*/       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_output()函数,这个是官方例程的发包函数,我们只需要将受到的数据包的大小以及数据发送到串口。

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字节是十进制201,则将整个包内容发往串口*/ 
      for (i = 0; i < receiveLen; i++){
        printf("%c", receiveBuffer[i]);
      }
  }

接下来就是获取数据包的长度receiveLen与数据receiveBuffer,通过串口打印出来。通过检测数据包的第42个字节为10,然后将收到的帧打印,我们使用 ping 192.168.2.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发送函数

/* 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初始化

#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、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 "FreeRTOS.h"
#include "task.h"
#include "stm32f4x7_eth.h"
#include "DP83848.h"

/************************************************
ALIENTEK 探索者STM32F407开发板 FreeRTOS实验6-1 
FreeRTOS任务创建和删除(动态方法)-库函数版本
************************************************/
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};
// 任务优先级
#define START_TASK_PRIO 1
// 任务堆栈大小
#define START_STK_SIZE 128
// 任务句柄
TaskHandle_t StartTask_Handler;
// 任务函数
void start_task(void *pvParameters);

// 任务优先级
#define TASK1_TASK_PRIO 3
// 任务堆栈大小
#define TASK1_STK_SIZE 128
// 任务句柄
TaskHandle_t Task1Task_Handler;
// 任务函数
void task1_task(void *pvParameters);

// 任务优先级
#define TASK2_TASK_PRIO 2
// 任务堆栈大小
#define TASK2_STK_SIZE 256
// 任务句柄
TaskHandle_t Task2Task_Handler;
// 任务函数
void task2_task(void *pvParameters);

int main(void){ 
  u8 MyMacAddr[6] = {0x08, 0x00, 0x06, 0x00, 0x00, 0x09}; 
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 中断分组配置 
  delay_init(168);// 初始化延时函数 
  uart_init(115200); // 初始化串口 
  LED_Init(); // 初始化LED端口
  DP83848Init(MyMacAddr); 
  // 创建开始任务
  xTaskCreate((TaskFunction_t)start_task, // 任务函数 
         (const char *)"start_task", // 任务名称 
         (uint16_t)START_STK_SIZE,  // 任务堆栈大小
         (void *)NULL, // 传递给任务函数的参数
         (UBaseType_t)START_TASK_PRIO, // 任务优先级 
         (TaskHandle_t *)&StartTask_Handler); // 任务句柄 
  vTaskStartScheduler(); // 开启任务调度
}
// 开始任务任务函数
void start_task(void *pvParameters){ 
  taskENTER_CRITICAL(); // 进入临界区 
  // 创建TASK1任务 
  xTaskCreate((TaskFunctiontask1_task,
  (const char *)"task1_task", 
  (uint16_t)TASK1_STK_SIZE, 
  (void *)NULL, 
  (UBaseType_t)TASK1_TASK_PRIO, 
  (TaskHandle_t *)&Task1Task_Handler);

  // 创建TASK2任务 
  xTaskCreate((TaskFunction_t)task2_task, 
  (const char *)"task2_task", 
  (uint16_t)TASK2_STK_SIZE, 
  (void *)NULL, 
  (UBaseType_t)TASK2_TASK_PRIO, 
  (TaskHandle_t *)&Task2Task_Handler); 
  vTaskDelete(StartTask_Handler); // 删除开始任务 
  taskEXIT_CRITICAL(); // 退出临界区
}
// task1任务函数
void task1_task(void *pvParameters){ 
  while (1) { 
    LED1 = !LED1; 
    LED0 = !LED0; 
    vTaskDelay(1000);
  }
}

void task2_task(void *pvParameters){ 
  while (1) { 
    DP83848Send(mydata, 60); 
    vTaskDelay(1000); 
  }
}

主要说一下创建的任务二(task2_task),周期性的发送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/1RLsQHhn_vnjngnw9yaL2aA?pwd=p2dw
提取码:p2dw

标签:DMA,void,0x00,STM32F407MAC,InitStructure,DP83848,GPIO,ETH,以太网
From: https://www.cnblogs.com/fuyunxiansen/p/18028741

相关文章

  • 基于STM32F407MAC与DP83848实现以太网通讯二(DP83848硬件配置以及寄存器)
    参考内容:DP83848数据表一、PHYDP83848功能模块图                     DP83848的硬件模块主要为:MII/RMII/SNI INTERFACES:用于与MAC数据传输的MII/RMII/SNI接口Transmit BLOCK:数据发送模块,将从外部MAC(例如STM32ETH外设的MAC)接收......
  • 基于STM32F407MAC与DP83848实现以太网通讯一(STM32以太网(ETH)外设)
    STM32F4xx可以通过以太网按照IEEE802.3-2002标准发送和接收数据。支持与外部物理层(PHY)相连的两个工业标准接口:默认情况下使用的介质独立接口(MII)(在IEEE802.3规范中定义)和简化介质独立接口(RMII)。具体的以太网(ETM)特性参考:STM32F4xx中文参考手册这里将重要的地方进......
  • 【计网实验】ARP包与以太网帧的分析
    ARP包与以太网帧的分析利用EVE-NG和Wireshark抓包:使用Linux终端对Linux2终端进行ping,在Linux终端的eth0网卡上进行抓包Linux端的MAC地址是00:50:00:00:02:00,Linux2端的MAC地址是00:50:00:00:03:00ARP包以太网帧头1:目的地址为ff:ff:ff:ff:ff:ff2:源地址为00:50:00:00:02......
  • 以太网环路保护切换技术ERPS解读
    前言  当前最新的车载网络广泛采用以太网作为主干网络,为了增强网络的可靠性,通常采用了环网拓扑结构,允许数据通过多条路径传输。然而,引入环网拓扑结构可能导致环路形成,进而带来广播风暴等潜在风险。为了规避这些问题,我们通常需要借助STP/RSTP等技术来防止环路形成,并在检测到通......
  • [90G] 以太网交换机 VSC7549-V/5CC、VSC7549TSN-V/5CC-VAO、VSC7549TSN-V/5CC 提供差
    1、VSC7549-V/5CC 90GEnterpriseSwitch概述VSC7549SPARX-5-90是一款90GbpsSMB/SME以太网交换机,支持1G、2.5G、5G和10G以太网端口组合。该设备提供了一组丰富的企业以太网交换功能。它使用多级多功能内容感知处理器(VCAP)技术,提供VLAN和QoS处理,通过智能帧处理和灵活的帧操作......
  • 有关以太网V2的MAC帧与PPP帧的封装成帧原理
    一、什么是封装成帧封装成帧是指数据链路层给上层交付的协议数据单元添加帧头和帧尾使之成为帧二、帧头和帧尾帧头:包含重要的控制信息帧尾:用于记录冗余码-------------->帧头和帧尾的作用之一是帧定界。这里的控制信息与冗余码在后面会详细解说。三、常见的帧类型:以......
  • 【RA6M3 HMI Board线下培训笔记】以太网+GUI技术实践篇-速通版
    @目录0.环境准备1.软件2.硬件3.示例文档和代码以太网+GUI技术实践技术路线图1.实践环节一:以太网外设的使用2.实践环节二:MQTT软件包的使用3.实践环节三:LVGL以太网数据监视器(比较综合的项目)4.实践环节四:使用SquarelineStudio开发UI总结[RT-Thread上文档详细介绍的链接]0.环境准......
  • TTE时间触发以太网交换机测试方法
    在本世纪初,TTE最早是由维也纳科技大学HermannKopetz赫尔曼·科佩茨教授等人提出来的,在国际上比较知名的TTE开发机构主要是以奥地利的TTTech公司为主,尔曼·科佩茨教授是该公司的创始人之一,这家公司是将教授的理论进行了产业化应用和推广,其中,开发的关于TTE网络产品包括:TTE交换机、......
  • 模拟适配器设计方案:360-基于10G以太网的模拟适配器
     基于10G以太网的模拟适配器一、产品概述   基于10G以太网的模拟适配器是一款分布式高速数据采集系统,实现多路AD的数据采集,并通过10G以太网光纤远距离传输到存储计算服务器,计算控制指令能通过光纤返回给数据卡进行IO信号控制。产品基于10G太网络,可迅......
  • 串口服务器485至以太网转换技术指南
    在现代工业和网络通信领域,串口服务器485至以太网转换技术扮演着至关重要的角色。本文旨在介绍这一技术的关键点和实际应用.串口服务器与RS-485接口串口服务器是一种网络设备,用于将串行通信(如RS-485)转换为以太网通信。RS-485接口是一种广泛应用的串行通信标准,它支持高速、远距离的多......