打印
[STM32F4]

STM32单片机示例:ETH_DP83848_DHCP_NonOS_Poll_F407

[复制链接]
82|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-3-18 09:17 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
目的
以太网是比较常用到的功能,这篇文章讲演示在STM32F407上启用以太网功能,使之能够加入网络中,通过DHCP获得IP地址,可以被Ping通。

基础说明
STM32F407是一个自带以太网控制器(ETH MAC)的单片机,只要外接以太网收发器(ETH PHY)就可以进行以太网通讯了。

不过通常来说以太网是一个相对复杂的东西,除了 MAC 和 PHY 外还需要很多软件上的协议支撑,才能方便的进行应用程序的开发,通常嵌入式设备中比较常用的是 LwIP 。

DHCP是一种可以让接入网络的设备可以动态获取IP地址的服务。通常作为一个可以联网工作的设备而言,通过DHCP自动获取IP地址是比较常用的方式。

使用 STM32CubeMX 可以方便的配置芯片自带的 ETH MAC ,可以配置 LwIP ,在 LwIP 中还可以选择一些 ETH PHY 芯片(比如本文的DP83848)。

在早期的版本中默认配置生成的代码在使用DHCP时,如果设备启动时没有插入网线,那么程序会一直卡在DHCP启动这里,目前版本中已经修复了这个问题。本文编写时使用的版本如下:

STM32CubeF4 Firmware Package V1.28.0 / 01-November-2023
Current version of LwIP supported by CubeMx: 2.1.2

主要配置
启用的外设与中间件:



时钟:



以太网:



LwIP:



堆栈:




关键代码
main.c 中一些手动添加的代码:

#include "main.h"
#include "lwip.h"

UART_HandleTypeDef huart6;

/* With GCC, small printf (option LD Linker->Libraries->Small printf set to 'Yes') calls __io_putchar() */
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch) // 实现__io_putchar函数
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */

PUTCHAR_PROTOTYPE
{
    HAL_UART_Transmit(&huart6, (uint8_t *)&ch, 1, 0xFFFF); // for printf()
    return ch;
}

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_LWIP_Init(); // 初始化网络功能
  MX_USART6_UART_Init();

  while (1)
  {
          MX_LWIP_Process(); // 处理网络相关事务

          static uint32_t previous = 0;
          if((HAL_GetTick() - previous)>=1000)
          {
                  previous = HAL_GetTick();
                  extern struct netif gnetif; // 网卡对象,在lwip.c文件中定义
                  // 打印时间和IP地址
                  printf("%ld - loop: ip addr %s\n", HAL_GetTick(), ip4addr_ntoa(netif_ip_addr4(&gnetif)));
          }
  }
}




lwip.c 中一些手动添加的代码:

/**
  * @brief  Notify the User about the network interface config status
  * @param  netif: the network interface
  */
static void ethernet_link_status_updated(struct netif *netif)
{
  if (netif_is_up(netif))
  {
          printf("%ld - link status callback: netif_is_up!\n", HAL_GetTick());
  }
  else /* netif is down */
  {
          printf("%ld - link status callback: netif_is_down!\n", HAL_GetTick());
  }
}



示例演示
连续Ping半个小时:



插拔网线测试:




示例链接
仓库地址: https://github.com/NaisuXu/STM32_MCU_Examples

本文中的示例位于仓库中 ETH_DP83848_DHCP_NonOS_Poll_F407 。

关于中断
以太网也是带中断的,以太网中断主要在接收、发送完成和错误等时候触发。

理论上来说可以在中断中接收数据,不过通常不应该在中断中处理耗时操作,所以更多的时候在中断中只是进行下标记,然后在主循环中处理。

未使用操作系统的情况下其实用中断和不用中断区别不是很大。官方也只在用了操作系统的情况下启用以太网中断,主要就是下面即可例程:

LwIP_HTTP_Server_Netconn_RTOS
LwIP_HTTP_Server_Socket_RTOS
LwIP_UDPTCP_Echo_Server_Netconn_RTOS

例程中首先是中断回调函数:

void ETH_IRQHandler(void)
{
  HAL_ETH_IRQHandler(&EthHandle);
}



回调函数中调用了HAL库对以太网中断的处理函数:

void HAL_ETH_IRQHandler(ETH_HandleTypeDef *heth)
{
  if (/* Packet received */)
  {
      HAL_ETH_RxCpltCallback(heth);
  }

  if (/* Packet transmitted */)
  {
      HAL_ETH_TxCpltCallback(heth);
  }

  if ( /* ETH DMA Error */)
  {
      HAL_ETH_ErrorCallback(heth);
  }
}




例程中各个中断的处理都是给了个信号量:

void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth)
{
  osSemaphoreRelease(RxPktSemaphore);
}

void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *heth)
{
  osSemaphoreRelease(TxPktSemaphore);
}

void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth)
{
   osSemaphoreRelease(RxPktSemaphore);
}



总结
到此为止网络部分已经可以正常工作了,接下来就可以开发网络应用了,主要是使用LwIP提供的一些接口进行数据交互,这方面内容可以参考官方例程和文档:
《UM1713 使用 LwIP TCP/IP 栈,在 STM32Cube 上开发应用》
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/Naisu_kun/article/details/136358210

使用特权

评论回复
沙发
小夏天的大西瓜| | 2024-3-18 16:50 | 只看该作者
STM32F407是一个自带以太网控制器(ETH MAC)的单片机,只要外接以太网收发器(ETH PHY)就可以进行以太网通讯了。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1364

主题

13994

帖子

8

粉丝