一、网络通信(1):LWIP的DHCP自动获取IP

基于正点原子探索者开发板(stm32f407zgt6),PHY芯片用的是LAN8720A,采用的是RMII接法

一、电路图

1、 LAN8720A外围电路图

在这里插入图片描述

2、 LAN8720A与MCU连接电路图

在这里插入图片描述

(1)PHY 芯片地址设置
LAN8720A 可以通过 PHYAD0 引脚来配置,该引脚与 RXER 引脚复用,芯片内部自带下
拉电阻,当硬复位结束后,LAN8720A 会读取该引脚电平,作为器件的 SMI 地址,接下拉电阻时(浮空也可以,因为芯片内部自带了下拉电阻),设置 SMI 地址为 0,当外接上拉电阻后,可以设置为 1。本章我们采用的是该引脚浮空,即设置 LAN8720 地址为 0。

(2)nINT/REFCLKO 引脚功能配置
nINT/REFCLKO 引脚可以用作中断输出,或者参考时钟输出。通过 LED2(nINTSEL)引脚设置,LED2 引脚的值在芯片复位后,被 LAN8720A 读取,当该引脚接上拉电阻(或浮空,内置上拉电阻),那么正常工作后,nINT/REFCLKO 引脚将作为中断输出引脚(选中 REF_CLK IN 模式)。当该引脚接下拉电阻时,正常工作后nINT/REFCLKO 引脚将作为参考时钟输出(选中 REF_CLK OUT 模式)。
在 REF_CLK IN 模式,外部必须提供 50Mhz 参考时钟给 LAN8720A 的 XTAL1(CLKIN)
引脚。在 REF_CLK OUT 模式,LAN8720A 可以外接 25Mhz 石英晶振,通过内部倍频到 50Mhz,然后通过 REFCLKO 引脚,输出 50Mhz 参考时钟给 MAC 控制器。这种方式,可以降低 BOM成本。
本章,我们设置 nINT/REFCLKO 引脚为参考时钟输出(REF_CLK OUT 模式),用于给
STM32F4 的 RMII 提供 50Mhz 参考时钟。

(3)1.2V 内部稳压器配置
LAN8720A 需要 1.2V 电压给 VDDCR 供电,不过芯片内部集成了 1.2V 稳压器,可以通过LED1(REGOFF)来配置是否使用内部稳压器,当不使用内部稳压器的时候,必须外部提供 1.2V电压给 VDDCR 引脚。这里我们使用内部稳压器,所以我们在 LED1 接下拉电阻(浮空也行,内置了下拉电阻),以控制开启内部 1.2V 稳压器。

二、STM32CnbeMX配置

1、配置系统时钟

在这里插入图片描述

2、配置ETH

配置ETH为RMII模式,PHY芯片LAN8720A的地址为0

在这里插入图片描述
选择user PHY,定义名称为LAN8720A
在这里插入图片描述
使能全局中断
在这里插入图片描述

3、配置LWIP

修改下面,其他默认
在这里插入图片描述

4、 更改网络通信相关的IO口和配置ETH_RESET复位脚

经过上述配置,CubeMX会自动配置网络相关的引脚,但有些引脚不一定和电路原理图对应,所以需要修改。下图是修改过的引脚,其中PD3脚是复位脚,设置为推挽输出,低电平
在这里插入图片描述

5、生成代码

将堆改大一点
在这里插入图片描述
C文件和H件分开
在这里插入图片描述

生成工程代码后,通过编译

三、修改代码

1、在ethernetif.c中添加ETH复位代码

void HAL_ETH_MspInit(ETH_HandleTypeDef* ethHandle)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(ethHandle->Instance==ETH)
  {
  /* USER CODE BEGIN ETH_MspInit 0 */

  /* USER CODE END ETH_MspInit 0 */
    /* Enable Peripheral clock */
    __HAL_RCC_ETH_CLK_ENABLE();

    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOG_CLK_ENABLE();
    /**ETH GPIO Configuration
    PC1     ------> ETH_MDC
    PA1     ------> ETH_REF_CLK
    PA2     ------> ETH_MDIO
    PA7     ------> ETH_CRS_DV
    PC4     ------> ETH_RXD0
    PC5     ------> ETH_RXD1
    PG11     ------> ETH_TX_EN
    PG13     ------> ETH_TXD0
    PG14     ------> ETH_TXD1
    */
    GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_13|GPIO_PIN_14;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
    HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

    /* Peripheral interrupt init */
    HAL_NVIC_SetPriority(ETH_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(ETH_IRQn);
  /* USER CODE BEGIN ETH_MspInit 1 */
  //添加的代码
  HAL_GPIO_WritePin(GPIOD,GPIO_PIN_3,GPIO_PIN_RESET);
  HAL_Delay(50);
  HAL_GPIO_WritePin(GPIOD,GPIO_PIN_3,GPIO_PIN_SET);
  /* USER CODE END ETH_MspInit 1 */
  }
}

2、在main.c中添加一些代码,获取由路由器分配的IP地址(路由器必须开启DHCP功能)

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
//添加代码
extern struct netif gnetif;
uint8_t ip4_number[4];
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_LWIP_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
 //添加代码
     MX_LWIP_Process(); //LWIP轮询
     ethernetif_set_link(netif_default);//重新插拔网线进行获取IP
     
    // 获取IP地址
     if(gnetif.ip_addr.addr)
	{	

		ip4_number[3] = gnetif.ip_addr.addr >> 24;
		ip4_number[2] = gnetif.ip_addr.addr >> 16;
		ip4_number[1] = gnetif.ip_addr.addr >> 8;
		ip4_number[0] = gnetif.ip_addr.addr >> 0;

	}
  }
  
  /* USER CODE END 3 */
}

四、测试

1、获取IP地址

网线连接开发板和路由器(路由器必须开启DHCP功能),编译代码后,进入在线调试模式全速运行,可以看到网口的灯在闪烁,并且得到IP地址,此处为192.168.2.156
在这里插入图片描述

2、PING一下获得的IP

Ping一下获取的IP地址,也没有问题
在这里插入图片描述

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: lwIP(轻量级IP协议栈)是一个用于嵌入式系统的开源TCP/IP协议栈。在lwIP中,我们可以使用DHCP(动态主机配置协议)来获取DNS(域名系统)服务器的地址。 要使用DHCP获取DNS服务器的地址,我们需要进行以下步骤: 1. 初始化lwIP协议栈: 首先,我们需要在嵌入式设备中初始化lwIP协议栈。这可以通过调用lwIP提供的初始化函数来完成。 2. 设置网络接口: 在初始化lwIP协议栈之后,我们需要设置网络接口,这可以通过调用lwIP提供的接口函数来完成。在设置网络接口时,我们可以指定使用DHCP作为IP地址和DNS服务器的配置方式。 3. 启用DHCP客户端: 接下来,我们需要启用lwIP中的DHCP客户端。这可以通过调用lwIP提供的DHCP客户端函数来完成。 4. 获取DNS服务器地址: 一旦DHCP客户端启用成功,在lwIP中,它将自动DHCP服务器进行通信,获取分配给设备的IP地址、子网掩码和DNS服务器地址等网络配置信息。我们可以通过访问lwIP中的相应数据结构来获取DNS服务器的地址。 5. 使用DNS服务器: 在获取到DNS服务器地址之后,我们就可以将其用于设备的DNS解析了。lwIP提供了DNS客户端函数,我们可以使用这些函数向DNS服务器发送解析请求,并获得相应的IP地址。 需要注意的是,以上步骤是基于lwIP协议栈的一般用法。具体使用方法可能因不同的应用需求和设备平台而有所不同,因此在实际应用中,可能需要查阅lwIP的文档和示例代码来进一步了解和使用特定的函数和配置选项。 ### 回答2: 在使用lwIP库进行网络开发时,可以通过Dynamic Host Configuration Protocol(DHCP)来获取DNS服务器。下面是一些使用lwIP获取DNS服务器的步骤: 1. 首先,确保lwIP库已经正确地配置和初始化。可以包括在系统中包含lwIP库并进行相应的初始化函数调用。 2. 在代码中,使用lwIP的API函数来启用DHCP功能。一般情况下,可以使用以下代码片段来启用DHCP: ``` dhcpc_start(netif); ``` 这将在指定的网络接口(netif)上启动DHCP客户端。 3. 当DHCP客户端成功获取IP地址时,可以通过以下代码来获取DNS服务器的配置信息: ``` dns_getserver(num_dns, &ip_addr); ``` 这将返回第num_dns个DNS服务器的IP地址,存储在`ip_addr`变量中。 4. 接下来,可以使用lwIP的其他相关API函数来处理和使用所获取的DNS服务器IP地址。这可能包括将其设置为系统的默认DNS服务器,或使用它进行DNS查询等。 请注意,上述步骤仅为获取DNS服务器的基本过程。在实际使用中,可能还需要处理一些错误情况、超时和其他特定的要求,以确保正常地获取到DNS服务器的IP地址。 ### 回答3: 在LWIP中,要使用DHCP获取DNS服务器,可以按照以下步骤进行操作: 1. 首先,配置LWIP库以使用DHCP。这可以通过在lwipopts.h文件中设置LWIP_DHCP为1来完成。这将启用LWIP库中的DHCP功能。 2. 接下来,在主应用程序的初始化代码中,创建一个与LWIP库关联的网络接口。可以使用函数netif_add()来完成这一操作。确保在调用netif_add()之前设置好LWIP库的ip、netmask和gateway。 3. 在网络接口关联后,可以注册一个回调函数来处理DHCP过程中的事件。可以使用函数dhcp_start()来启动DHCP过程,并将回调函数注册到网络接口。回调函数将在DHCP过程中触发不同的事件,例如IP地址和DNS服务器地址的获取。 4. 在回调函数中,可以使用netif_ip_addr_get()函数来获取分配给设备的IP地址。类似地,可以使用dhcp_supplied_dns()函数来获取DHCP服务器提供的DNS服务器地址。将这些地址存储在适当的变量中,以便在需要时使用。 5. 最后,在应用程序的其他部分中,可以使用存储的DNS服务器地址来配置设备或执行其他与网络通信相关的任务。 需要注意的是,DHCP过程可能需要一些时间来完成,因此在操作DNS服务器之前,确保DHCP过程已经完成并且DNS服务器地址已经获取。 以上是使用LWIP库通过DHCP获取DNS服务器的基本步骤。根据具体的应用需求和网络环境,还可以进一步配置其他参数和处理其他事件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值