【ESP32-IDF笔记】20-配置以太网网络(W5500)
环境配置
Visual Studio Code :版本1.98.2
ESP32:ESP32-S3
ESP-IDF:V5.4
模块:W5500,SPI通讯协议
组件支持:esp_eth 官方的ethernet 以太网组件
W5500介绍
介绍
W5500 是一款全硬件 TCP/IP 嵌入式以太网控制器,为嵌入式系统提供了更加简易的互联网连接方案。W5500 集成了 TCP/IP 协议栈,10/100M 以太网数据链路层(MAC) 及物理层(PHY),使得用户使用单芯片就能够在他们的应用中拓展网络连接。久经市场考验的 WIZnet 全硬件 TCP/IP 协议栈支持 TCP,UDP,IPv4,ICMP,ARP,IGMP 以及 PPPoE协议。W5500 内嵌 32K 字节片上缓存以供以太网包处理。如果你使用 W5500, 你只需要一些简单的 Socket 编程就能实现以太网应用。这将会比其他嵌入式以太网方案 更加快捷、简便。用户可以同时使用 8 个硬件 Socket 独立通讯。W5500 提供了 SPI(外设串行接口)从而能够更加容易与外设 MCU 整合。而且, W5500 的使用了新的高效 SPI 协议支持 80MHz 速率,从而能够更好的实现高速网络通讯。 为了减少系统能耗,W5500 提供了网络唤醒模式(WOL)及掉电模式供客户选择使用
特点
- 支持硬件 TCP/IP 协议:TCP, UDP, ICMP, IPv4, ARP, IGMP, PPPoE
- 支持 8 个独立端口(Socket)同时通讯
- 支持掉电模式
- 支持网络唤醒
- 支持高速串行外设接口(SPI 模式 0,3)
- 内部 32K 字节收发缓存
- 内嵌 10BaseT/100BaseTX 以太网物理层(PHY)
- 支持自动协商(10/100-Based 全双工/半双工)
- 不支持 IP 分片
- 3.3V 工作电压,I/O 信号口 5V 耐压;
- LED 状态显示(全双工/半双工,网络连接,网络速度,活动状态)
- 48 引脚 LQFP 无铅封装(7x7mm, 0.5mm 间距)
以太网介绍
以太网基本概念
以太网是一种异步的带冲突检测的载波侦听多路访问 (CSMA/CD) 协议/接口。通常来说,以太网不太适用于低功耗应用。然而,得益于其广泛的部署、高效的网络连接、高数据率以及范围不限的可扩展性,几乎所有的有线通信都可以通过以太网进行。
符合 IEEE 802.3 标准的正常以太网帧的长度在 64 至 1518 字节之间,由五个或六个不同的字段组成:目的地 MAC 地址 (DA)、源 MAC 地址 (SA)、类型/长度字段、数据有效载荷字段、可选的填充字段和帧校验序列字段 (CRC)。此外,在以太网上传输时,以太网数据包的开头需附加 7 字节的前导码和 1 字节的帧起始符 (SOF)。
因此,双绞线上的通信如图所示:
前导码和帧起始符
前导码包含 7 字节的 55H
,作用是使接收器在实际帧到达之前锁定数据流。
帧前界定符 (SFD) 为二进制序列 10101011
(物理介质层可见)。有时它也被视作前导码的一部分。
在传输和接收数据时,协议将自动从数据包中生成/移除前导码和帧起始符。
目的地址 (DA)
目的地址字段包含一个 6 字节长的设备 MAC 地址,数据包将发送到该地址。如果 MAC 地址第一个字节中的最低有效位是 1,则该地址为组播地址。例如,01-00-00-F0-00 和 33-45-67-89-AB-CD 是组播地址,而 00-00-00-F0-00 和 32-45-67-89-AB-CD 不是。
带有组播地址的数据包将到达选定的一组以太网节点,并发挥重要作用。如果目的地址字段是保留的多播地址,即 FF-FF-FF-FF-FF-FF,则该数据包是一个广播数据包,指向共享网络中的每个对象。如果 MAC 地址的第一个字节中的最低有效位为 0,则该地址为单播地址,仅供寻址节点使用。
通常,EMAC 控制器会集成接收过滤器,用于丢弃或接收带有组播、广播和/或单播目的地址的数据包。传输数据包时,由主机控制器将所需的目标地址写入传输缓冲区。
源地址 (SA)
源地址字段包含一个 6 字节长的节点 MAC 地址,以太网数据包通过该节点创建。以太网的用户需为所使用的任意控制器生成唯一的 MAC 地址。MAC 地址由两部分组成:前三个字节称为组织唯一标识符 (OUI),由 IEEE 分配;后三个字节是地址字节,由购买 OUI 的公司配置。有关 ESP-IDF 中使用的 MAC 地址的详细信息,请参见 MAC 地址分配。
传输数据包时,由主机控制器将分配的源 MAC 地址写入传输缓冲区。
类型/长度
类型/长度字段长度为 2 字节。如果其值 <= 1500(十进制),则该字段为长度字段,指定在数据字段后的非填充数据量;如果其值 >= 1536,则该字段值表示后续数据包所属的协议。以下为该字段的常见值:
- IPv4 = 0800H
- IPv6 = 86DDH
- ARP = 0806H
使用专有网络的用户可以将此字段配置为长度字段。然而,对于使用互联网协议 (IP) 或地址解析协议 (ARP) 等协议的应用程序,在传输数据包时,应将此字段配置为协议规范定义的适当类型。
数据有效载荷
数据有效载荷字段是一个可变长度的字段,长度从 0 到 1500 字节不等。更大的数据包会因违反以太网标准而被大多数以太网节点丢弃。
数据有效载荷字段包含客户端数据,如 IP 数据报。
填充及帧校验序列 (FCS)
填充字段是一个可变长度的字段。数据有效载荷较小时,将添加填充字段以满足 IEEE 802.3 规范的要求。
以太网数据包的 DA、SA、类型、数据有效载荷和填充字段共计必须不小于 60 字节。加上所需的 4 字节 FCS 字段,数据包的长度必须不小于 64 字节。如果数据有效载荷字段小于 46 字节,则需要加上一个填充字段。
帧校验序列字段 (FCS) 长度为 4 字节,其中包含一个行业标准的 32 位 CRC,该 CRC 是根据 DA、SA、类型、数据有效载荷和填充字段的数据计算的。鉴于计算 CRC 的复杂性,硬件通常会自动生成一个有效的 CRC 进行传输。否则,需由主机控制器生成 CRC 并将其写入传输缓冲区。
通常情况下,主机控制器无需关注填充字段和 CRC 字段,因为这两部分可以在传输或接收时由硬件 EMAC 自动生成或验证。然而,当数据包到达时,填充字段和 CRC 字段将被写入接收缓冲区。因此,如果需要的话,主机控制器也可以对它们进行评估。
注意
除了上述的基本数据帧,在 10/100 Mbps 以太网中还有两种常见的帧类型:控制帧和 VLAN 标记帧。ESP-IDF 不支持这两种帧类型。
配置 MAC 和 PHY
以太网驱动器由两部分组成:MAC 和 PHY。
根据以太网板设计,需要分别为 MAC 和 PHY 配置必要的参数,通过两者完成驱动程序的安装。
MAC 的相关配置可以在 eth_mac_config_t
中找到,具体包括:
-
eth_mac_config_t::sw_reset_timeout_ms
:软件复位超时值,单位为毫秒。通常,MAC 复位应在 100 ms 内完成。 -
eth_mac_config_t::rx_task_stack_size
和eth_mac_config_t::rx_task_prio
:MAC 驱动会创建一个专门的任务来处理传入的数据包,这两个参数用于设置该任务的堆栈大小和优先级。 -
eth_mac_config_t::flags
:指定 MAC 驱动应支持的额外功能,尤其适用于某些特殊情况。这个字段的值支持与以ETH_MAC_FLAG_
为前缀的宏进行 OR 运算。例如,如果要求 MAC 驱动程序在 cache 禁用时仍能正常工作,那么则需要用ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE
配置这个字段。
PHY 的相关配置可以在 eth_phy_config_t
中找到,具体包括:
-
eth_phy_config_t::phy_addr
:同一条 SMI 总线上可以存在多个 PHY 设备,所以有必要为各个 PHY 设备分配唯一地址。通常,这个地址是在硬件设计期间,通过拉高/拉低一些 PHY strapping 管脚来配置的。根据不同的以太网开发板,可配置值为0
到15
。需注意,如果 SMI 总线上仅有一个 PHY 设备,将该值配置为-1
,即可使驱动程序自动检测 PHY 地址。 -
eth_phy_config_t::reset_timeout_ms
:复位超时值,单位为毫秒。通常,PHY 复位应在 100 ms 内完成。 -
eth_phy_config_t::autonego_timeout_ms
:自动协商超时值,单位为毫秒。以太网驱动程序会与链路另一端的设备进行自协商,以确定连接的最佳双工模式和速率。此值通常取决于电路板上 PHY 设备的性能。 -
eth_phy_config_t::reset_gpio_num
:如果开发板同时将 PHY 复位管脚连接至了任意 GPIO 管脚,请使用该字段进行配置。否则,配置为-1
。 -
eth_phy_config_t::hw_reset_assert_time_us
:PHY 复位引脚被置为有效状态的时间(以微秒为单位)。将该值配置为0
,即可使用芯片默认的复位时长。 -
eth_phy_config_t::post_hw_reset_delay_ms
:PHY 硬件复位完成后的等待时间(以毫秒为单位)。将该值配置为0
,即可使用芯片默认的等待时长,配置为-1
,表示执行 PHY 硬件复位后不等待。
ESP-IDF 在宏 ETH_MAC_DEFAULT_CONFIG
和 ETH_PHY_DEFAULT_CONFIG
中为 MAC 和 PHY 提供了默认配置。
创建 MAC 和 PHY 实例
以太网驱动是以面向对象的方式实现的。对 MAC 和 PHY 的任何操作都应基于实例。
SPI-Ethernet 模块
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); // 应用默认的通用 MAC 配置
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); // 应用默认的 PHY 配置
phy_config.phy_addr = CONFIG_EXAMPLE_ETH_PHY_ADDR; // 根据开发板设计更改 PHY 地址
phy_config.reset_gpio_num = CONFIG_EXAMPLE_ETH_PHY_RST_GPIO; // 更改用于 PHY 复位的 GPIO
// 安装 GPIO 中断服务(因为 SPI-Ethernet 模块为中断驱动)
gpio_install_isr_service(0);
// 配置 SPI 总线
spi_device_handle_t spi_handle = NULL;
spi_bus_config_t buscfg = {.miso_io_num = CONFIG_EXAMPLE_ETH_SPI_MISO_GPIO,.mosi_io_num = CONFIG_EXAMPLE_ETH_SPI_MOSI_GPIO,.sclk_io_num = CONFIG_EXAMPLE_ETH_SPI_SCLK_GPIO,.quadwp_io_num = -1,.quadhd_io_num = -1,
};
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1));
// 配置 SPI 从机设备
spi_device_interface_config_t spi_devcfg = {.mode = 0,.clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,.spics_io_num = CONFIG_EXAMPLE_ETH_SPI_CS_GPIO,.queue_size = 20
};
/* dm9051 ethernet driver is based on spi driver */
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(SPI2_HOST, &spi_devcfg);
w5500_config.int_gpio_num = spi_eth_module_config->int_gpio;
w5500_config.poll_period_ms = spi_eth_module_config->polling_ms;
esp_eth_mac_t *mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
esp_eth_phy_t *phy = esp_eth_phy_new_w5500(&phy_config);
安装驱动程序
安装以太网驱动程序需要结合 MAC 和 PHY 实例,并在 esp_eth_config_t
中配置一些额外的高级选项(即不仅限于 MAC 或 PHY 的选项):
-
esp_eth_config_t::mac
:由 MAC 生成器创建的实例(例如esp_eth_mac_new_esp32()
)。 -
esp_eth_config_t::phy
:由 PHY 生成器创建的实例(例如esp_eth_phy_new_ip101()
)。 -
esp_eth_config_t::check_link_period_ms
:以太网驱动程序会启用操作系统定时器来定期检查链接状态。该字段用于设置间隔时间,单位为毫秒。 -
esp_eth_config_t::stack_input
:在大多数的以太网物联网应用中,驱动器接收的以太网帧会被传递到上层(如 TCP/IP 栈)。经配置,该字段为负责处理传入帧的函数。可以在安装驱动程序后,通过函数esp_eth_update_input_path()
更新该字段。该字段支持在运行过程中进行更新。 -
esp_eth_config_t::on_lowlevel_init_done
和esp_eth_config_t::on_lowlevel_deinit_done
:这两个字段用于指定钩子函数,当去初始化或初始化低级别硬件时,会调用钩子函数。
ESP-IDF 在宏 ETH_DEFAULT_CONFIG
中为安装驱动程序提供了一个默认配置。
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); // 应用默认驱动程序配置
esp_eth_handle_t eth_handle = NULL; // 驱动程序安装完毕后,将得到驱动程序的句柄
esp_eth_driver_install(&config, ð_handle); // 安装驱动程序
以太网驱动程序包含事件驱动模型,该模型会向用户空间发送有用及重要的事件。安装以太网驱动程序之前,需要首先初始化事件循环。有关事件驱动编程的更多信息,请参考 事件循环库。
/** 以太网事件的事件处理程序 */
static void eth_event_handler(void *arg, esp_event_base_t event_base,int32_t event_id, void *event_data)
{uint8_t mac_addr[6] = {0};/* 可从事件数据中获得以太网驱动句柄 */esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;switch (event_id) {case ETHERNET_EVENT_CONNECTED:esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);ESP_LOGI(TAG, "Ethernet Link Up");ESP_LOGI(TAG, "Ethernet HW Addr %02x:%02x:%02x:%02x:%02x:%02x",mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);break;case ETHERNET_EVENT_DISCONNECTED:ESP_LOGI(TAG, "Ethernet Link Down");break;case ETHERNET_EVENT_START:ESP_LOGI(TAG, "Ethernet Started");break;case ETHERNET_EVENT_STOP:ESP_LOGI(TAG, "Ethernet Stopped");break;default:break;}
}esp_event_loop_create_default(); // 创建一个在后台运行的默认事件循环
esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL); // 注册以太网事件处理程序(用于在发生 link up/down 等事件时,处理特定的用户相关内容)
启动以太网驱动程序
安装驱动程序后,可以立即启动以太网。
esp_eth_start(eth_handle); // 启动以太网驱动程序状态机
连接驱动程序至 TCP/IP 协议栈
现在,以太网驱动程序已经完成安装。但对应 OSI(开放式系统互连模型)来看,目前阶段仍然属于第二层(即数据链路层)。这意味着可以检测到 link up/down 事件,获得用户空间的 MAC 地址,但无法获得 IP 地址,当然也无法发送 HTTP 请求。ESP-IDF 中使用的 TCP/IP 协议栈是 LwIP,关于 LwIP 的更多信息,请参考 LwIP。
要将以太网驱动程序连接至 TCP/IP 协议栈,需要以下三步:
- 为以太网驱动程序创建网络接口
- 将网络接口连接到以太网驱动程序
- 注册 IP 事件处理程序
有关网络接口的更多信息,请参考 Network Interface。
/** IP_EVENT_ETH_GOT_IP 的事件处理程序 */
static void got_ip_event_handler(void *arg, esp_event_base_t event_base,int32_t event_id, void *event_data)
{ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;const esp_netif_ip_info_t *ip_info = &event->ip_info;ESP_LOGI(TAG, "Ethernet Got IP Address");ESP_LOGI(TAG, "~~~~~~~~~~~");ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip));ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw));ESP_LOGI(TAG, "~~~~~~~~~~~");
}esp_netif_init()); // 初始化 TCP/IP 网络接口(在应用程序中应仅调用一次)
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH(); // 应用以太网的默认网络接口配置
esp_netif_t *eth_netif = esp_netif_new(&cfg); // 为以太网驱动程序创建网络接口esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle)); // 将以太网驱动程序连接至 TCP/IP 协议栈
esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL); // 注册用户定义的 IP 事件处理程序
esp_eth_start(eth_handle); // 启动以太网驱动程序状态机
警告!
推荐在完成整个以太网驱动和网络接口的初始化后,再注册用户定义的以太网/IP 事件处理程序,也就是把注册事件处理程序作为启动以太网驱动程序的最后一步。这样可以确保以太网驱动程序或网络接口将首先执行以太网/IP 事件,从而保证在执行用户定义的处理程序时,系统处于预期状态。
以太网驱动程序的杂项控制
以下功能只支持在安装以太网驱动程序后调用。
- 关闭以太网驱动程序:
esp_eth_stop()
- 更新以太网数据输入路径:
esp_eth_update_input_path()
- 获取/设置以太网驱动程序杂项内容:
esp_eth_ioctl()
/* 获取 MAC 地址 */
uint8_t mac_addr[6];
memset(mac_addr, 0, sizeof(mac_addr));
esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);
ESP_LOGI(TAG, "Ethernet MAC Address: %02x:%02x:%02x:%02x:%02x:%02x",mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);/* 获取 PHY 地址 */
int phy_addr = -1;
esp_eth_ioctl(eth_handle, ETH_CMD_G_PHY_ADDR, &phy_addr);
ESP_LOGI(TAG, "Ethernet PHY Address: %d", phy_addr);
数据流量控制
受 RAM 大小限制,在网络拥堵时,MCU 上的以太网通常仅能处理有限数量的帧。发送站的数据传输速度可能快于对等端的接收能力。以太网数据流量控制机制允许接收节点向发送方发出信号,要求暂停传输,直到接收方跟上。这项功能是通过暂停帧实现的,该帧定义在 IEEE 802.3x 中。
暂停帧是一种特殊的以太网帧,用于携带暂停命令,其 EtherType 字段为 0x8808
,控制操作码为 0x0001
。只有配置为全双工操作的节点组可以发送暂停帧。当节点组希望暂停链路的另一端时,它会发送一个暂停帧到 48 位的保留组播地址 01-80-C2-00-00-01
。暂停帧中也包括请求暂停的时间段,以两字节的整数形式发送,值的范围从 0
到 65535
。
安装以太网驱动程序后,数据流量控制功能默认禁用,可以通过以下方式启用此功能:
bool flow_ctrl_enable = true;
esp_eth_ioctl(eth_handle, ETH_CMD_S_FLOW_CTRL, &flow_ctrl_enable);
需注意,暂停帧是在自动协商期间由 PHY 向对等端公布的。只有当链路两端都支持暂停帧时,以太网驱动程序才会发送暂停帧。
应用示例
首先在ESP32IDF 配置中勾选使用W5500
w5500_config.h
#ifndef _W5500_CONFIG_H
#define _W5500_CONFIG_H
#ifdef __cplusplus
extern "C"{
#endif/*
说明:基于ESP32IDF 官方的ethernet 以太网驱动实现W5500
需要包含组件:esp_eth
代码基于只挂在一个W5500以太网口的情况,挂在多个网口是需另外处理
*/
#include "esp_eth_driver.h"
#include "esp_err.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"// W5500 静态IP设置
#define W5500_STATIC_IP 0 //1-使用静态IP,0-使用动态IP
#if W5500_STATIC_IP
#define W5500_IP "192.168.1.168" // IP地址
#define W5500_GateWwy "192.168.1.1" //网关
#define W5500_NetMask "255.255.255.0" // 子网掩码
#endif/// @brief W5500 配置的结构体 ,没用到的设置为-1
typedef struct
{spi_host_device_t host_id;gpio_num_t miso_io_num;gpio_num_t mosi_io_num;gpio_num_t sclk_io_num;gpio_num_t cs_io_num;gpio_num_t int_io_num;gpio_num_t rst_io_num;/* data */
}w5500_config_t;/*** @brief 根据乐鑫物联网开发框架配置初始化以太网驱动程序** @param[in] cfg 一些需要配置的参数* @param[out] eth_handles_out 已初始化的以太网句柄* @param[out] eth_cnt_out 已初始化的以太网数量* @return* - ESP_OK 初始化成功* - ESP_ERR_INVALID_ARG 当传递无效指针时* - ESP_ERR_NO_MEM 当没有内存来分配以太网驱动程序句柄数组时* - ESP_FAIL 在任何其他故障情况下*/
esp_err_t w5500_init(w5500_config_t *cfg);/*** @brief 注销w5500*/
esp_err_t w5500_deinit(void);// W5500 测试示例
void w5500_test(void);
#ifdef __cplusplus
}
#endif#endif
w5500_config.c
#include "w5500_config.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_mac.h"
#include "esp_netif.h"
#include "esp_eth.h"
#include "esp_event.h"
#include <stdio.h>
#include <string.h>#define CONFIG_EXAMPLE_ETH_SPI_INT0_GPIO GPIO_NUM_9
#define CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ 16 // 16MHztypedef struct
{uint8_t spi_cs_gpio;int8_t int_gpio;uint32_t polling_ms;int8_t phy_reset_gpio;uint8_t phy_addr;uint8_t *mac_addr;
} spi_eth_module_config_t;static const char *TAG = "W5500->";static bool gpio_isr_svc_init_by_eth = false; // 表示我们已经初始化了GPIO中断服务例程(ISR) 服务。
static spi_host_device_t host_id = SPI2_HOST;
esp_eth_handle_t eth_handles = NULL;/** 以太网事件的事件处理程序 */
static void eth_event_handler(void *arg, esp_event_base_t event_base,int32_t event_id, void *event_data)
{uint8_t mac_addr[6] = {0};/* 我们可以从事件数据中获取以太网驱动程序句柄。 */esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;switch (event_id){case ETHERNET_EVENT_CONNECTED: // 以太网链路已连接esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);ESP_LOGI(TAG, "Ethernet Link Up");ESP_LOGI(TAG, "Ethernet HW Addr %02x:%02x:%02x:%02x:%02x:%02x",mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);break;case ETHERNET_EVENT_DISCONNECTED: // 以太网链路断开ESP_LOGI(TAG, "Ethernet Link Down");break;case ETHERNET_EVENT_START: // 以太网已启动ESP_LOGI(TAG, "Ethernet Started");break;case ETHERNET_EVENT_STOP: // 以太网停止ESP_LOGI(TAG, "Ethernet Stopped");break;default:break;}
}/** 获取到IP地址 的事件处理程序 */
static void got_ip_event_handler(void *arg, esp_event_base_t event_base,int32_t event_id, void *event_data)
{ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;const esp_netif_ip_info_t *ip_info = &event->ip_info;ESP_LOGI(TAG, "Ethernet Got IP Address");ESP_LOGI(TAG, "~~~~~~~~~~~");ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip));ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw));ESP_LOGI(TAG, "~~~~~~~~~~~");
}/*** @brief SPI总线初始化(供以太网SPI模块使用)** @return* - ESP_OK 成功*/
static esp_err_t spi_bus_init(w5500_config_t *cfg)
{ESP_LOGI(TAG, "SPI bus init start!");// Init SPI busspi_bus_config_t buscfg = {.miso_io_num = cfg->miso_io_num,.mosi_io_num = cfg->mosi_io_num,.sclk_io_num = cfg->sclk_io_num,.quadwp_io_num = -1,.quadhd_io_num = -1,};ESP_ERROR_CHECK(spi_bus_initialize(cfg->host_id, &buscfg, SPI_DMA_CH_AUTO));host_id = cfg->host_id;ESP_LOGI(TAG, "SPI bus init DONE!");return ESP_OK;
}/*** @brief 以太网SPI模块初始化** @param[in] spi_eth_module_config 特定的SPI以太网模块配置* @param[out] mac_out 可选地返回以太网MAC对象* @param[out] phy_out 可选地返回以太网物理层(PHY)对象* @return
* - 如果初始化成功,返回`esp_eth_handle_t`* - 如果初始化失败,返回`NULL` */
static esp_eth_handle_t eth_init_spi(spi_eth_module_config_t *spi_eth_module_config, esp_eth_mac_t **mac_out, esp_eth_phy_t **phy_out)
{esp_eth_handle_t ret = NULL;// 将通用MAC和PHY配置初始化为默认值eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();// 根据板卡特定配置更新物理层(PHY)配置。phy_config.phy_addr = spi_eth_module_config->phy_addr;phy_config.reset_gpio_num = spi_eth_module_config->phy_reset_gpio;// 安装通用输入输出中断服务程序(GPIO ISR)处理程序,以便能够处理串行外设接口(SPI)以太网模块的中断if (spi_eth_module_config->int_gpio >= 0){ESP_ERROR_CHECK(gpio_install_isr_service(0));gpio_isr_svc_init_by_eth = true;}// 为特定的SPI模块配置SPI接口spi_device_interface_config_t spi_devcfg = {.mode = 0,.clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,.queue_size = 20,.spics_io_num = spi_eth_module_config->spi_cs_gpio,};// W5500以太网驱动基于SPI驱动eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(host_id, &spi_devcfg); //// 设置SPI模块使用的剩余GPIO编号和配置。w5500_config.int_gpio_num = spi_eth_module_config->int_gpio;w5500_config.poll_period_ms = spi_eth_module_config->polling_ms;esp_eth_mac_t *mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);esp_eth_phy_t *phy = esp_eth_phy_new_w5500(&phy_config);// 将以太网驱动程序初始化为默认设置并安装它。esp_eth_handle_t eth_handle = NULL;esp_eth_config_t eth_config_spi = ETH_DEFAULT_CONFIG(mac, phy);ESP_GOTO_ON_FALSE(esp_eth_driver_install(ð_config_spi, ð_handle) == ESP_OK, NULL, err, TAG, "SPI Ethernet driver install failed");// SPI以太网模块可能没有烧录出厂MAC地址,我们可以手动设置。if (spi_eth_module_config->mac_addr != NULL){ESP_GOTO_ON_FALSE(esp_eth_ioctl(eth_handle, ETH_CMD_S_MAC_ADDR, spi_eth_module_config->mac_addr) == ESP_OK,NULL, err, TAG, "SPI Ethernet MAC address config failed");}if (mac_out != NULL){*mac_out = mac;}if (phy_out != NULL){*phy_out = phy;}return eth_handle;
err:if (eth_handle != NULL){esp_eth_driver_uninstall(eth_handle);}if (mac != NULL){mac->del(mac);}if (phy != NULL){phy->del(phy);}return ret;
}/// @brief 将以太网驱动程序附加到TCP/IP协议栈,同时设置静态IP
/// @param
/// @return
esp_err_t w5500_set_static_ip(void)
{ESP_LOGI(TAG, "start set static IP");if (eth_handles == NULL){ESP_LOGI(TAG, "Ethernet handles cannot be NULL");return ESP_ERR_INVALID_ARG;}esp_netif_t *eth_netifs = NULL;esp_eth_netif_glue_handle_t eth_netif_glues;//为SPI以太网创建esp-netif实例 esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH();// 当仅使用一个以太网接口且不需要修改默认的esp-netif配置参数时,可以调用ESP_NETIF_DEFAULT_ETH(),此时的为动态IP#if W5500_STATIC_IP //是否使用静态IPesp_netif_config_t cfg = { // 应用以太网的默认网络接口配置.base = &esp_netif_config,.stack = ESP_NETIF_NETSTACK_DEFAULT_ETH,}; #elseesp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH(); // 应用以太网的默认网络接口配置,动态分配IP#endifeth_netifs = esp_netif_new(&cfg); 为以太网驱动程序创建网络接口eth_netif_glues = esp_eth_new_netif_glue(eth_handles);// 将以太网驱动程序附加到TCP/IP协议栈ESP_ERROR_CHECK(esp_netif_attach(eth_netifs, eth_netif_glues));#if W5500_STATIC_IP // 设置静态IP地址 ESP_ERROR_CHECK(esp_netif_dhcpc_stop(eth_netifs)); // 注意接口不能用错esp_netif_ip_info_t ip_info;memset(&ip_info, 0, sizeof(esp_netif_ip_info_t));ip_info.ip.addr = esp_ip4addr_aton((const char *)W5500_IP);ip_info.netmask.addr = esp_ip4addr_aton((const char *)W5500_GateWwy);ip_info.gw.addr = esp_ip4addr_aton((const char *)W5500_NetMask);esp_err_t err = 0;err = esp_netif_set_ip_info(eth_netifs, &ip_info);if (ESP_OK == err)ESP_LOGI(TAG, "Set static IP OK");elseESP_LOGI(TAG, "Set static IP error: %d", err);
#endifreturn ESP_OK;
}
esp_err_t w5500_init(w5500_config_t *cfg)
{ESP_LOGI(TAG, "W5500 init start!");esp_err_t ret = ESP_OK;ESP_GOTO_ON_FALSE(cfg != NULL, ESP_ERR_INVALID_ARG, err, TAG, "invalid arguments: initialized handles array or number of interfaces");eth_handles = malloc(sizeof(esp_eth_handle_t));ESP_GOTO_ON_FALSE(eth_handles != NULL, ESP_ERR_NO_MEM, err, TAG, "no memory");// 初始化SPIESP_GOTO_ON_ERROR(spi_bus_init(cfg), err, TAG, "SPI bus init failed");// 获取本地macuint8_t base_mac_addr[ETH_ADDR_LEN];ESP_GOTO_ON_ERROR(esp_efuse_mac_get_default(base_mac_addr), err, TAG, "get EFUSE MAC failed"); // 获取ESP32出厂编程的基本 MAC 地址uint8_t local_mac[ETH_ADDR_LEN];esp_derive_local_mac(local_mac, base_mac_addr); // 从通用MAC地址派生本地MAC地址。// 初始化特定的SPI以太网模块配置(片选GPIO、中断GPIO等)spi_eth_module_config_t spi_eth_module_config = {.int_gpio = cfg->int_io_num,.spi_cs_gpio = cfg->cs_io_num,.phy_reset_gpio = cfg->rst_io_num,.mac_addr = local_mac,.phy_addr = 1,.polling_ms = 0,};eth_handles = eth_init_spi(&spi_eth_module_config, NULL, NULL);w5500_set_static_ip(); //将以太网驱动程序附加到TCP/IP协议栈,同时设置静态IP// 注册用户定义的事件处理程序ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL));ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL));ESP_ERROR_CHECK(esp_eth_start(eth_handles));ESP_GOTO_ON_FALSE(eth_handles, ESP_FAIL, err, TAG, "SPI Ethernet init failed");return ret;
err:free(eth_handles);return ret;
}esp_err_t w5500_deinit(void)
{if (eth_handles == NULL){ESP_LOGI(TAG, "Ethernet handles cannot be NULL");return ESP_ERR_INVALID_ARG;}esp_eth_mac_t *mac = NULL;esp_eth_phy_t *phy = NULL;if (eth_handles != NULL){esp_eth_get_mac_instance(eth_handles, &mac);esp_eth_get_phy_instance(eth_handles, &phy);ESP_RETURN_ON_ERROR(esp_eth_driver_uninstall(eth_handles), TAG, "Ethernet %p uninstall failed", eth_handles);}if (mac != NULL){mac->del(mac);}if (phy != NULL){phy->del(phy);}spi_bus_free(host_id);
#if (CONFIG_EXAMPLE_ETH_SPI_INT0_GPIO >= 0) || (CONFIG_EXAMPLE_ETH_SPI_INT1_GPIO > 0)// 我们安装了GPIO中断服务例程(ISR),所以也需要卸载它。// 不过这里要小心,因为该服务可能被其他功能使用!if (gpio_isr_svc_init_by_eth){ESP_LOGW(TAG, "uninstalling GPIO ISR service!");gpio_uninstall_isr_service();}
#endiffree(eth_handles);return ESP_OK;
}void w5500_test(void)
{// 初始化TCP/IP网络接口,即esp-netif(在应用程序中应仅调用一次)ESP_ERROR_CHECK(esp_netif_init());// 创建在后台运行的默认事件循环。ESP_ERROR_CHECK(esp_event_loop_create_default());w5500_config_t w5500_cfg = {.host_id = SPI2_HOST,.miso_io_num = GPIO_NUM_13,.mosi_io_num = GPIO_NUM_11,.sclk_io_num = GPIO_NUM_12,.cs_io_num = GPIO_NUM_10,.int_io_num = GPIO_NUM_9,.rst_io_num = GPIO_NUM_NC,};ESP_ERROR_CHECK(w5500_init(&w5500_cfg));
}
log输出
在main文件添加头文件,并调用w5500_test()
#include "w5500_config.h"w5500_test();
初始化正常时,LOG输出如下
相关文章:
【ESP32-IDF笔记】20-配置以太网网络(W5500)
环境配置 Visual Studio Code :版本1.98.2 ESP32:ESP32-S3 ESP-IDF:V5.4 模块:W5500,SPI通讯协议 组件支持:esp_eth 官方的ethernet 以太网组件 W5500介绍 介绍 W5500 是一款全硬件 TCP/IP 嵌入式以太网…...
python源码打包为可执行的exe文件
文章目录 简单的方式(PyInstaller)特点步骤安装 PyInstaller打包脚本得到.exe文件 简单的方式(PyInstaller) 特点 支持 Python 3.6打包为单文件(–onefile)或文件夹形式自动处理依赖项 步骤 安装 PyIns…...
在vscode终端中运行npm命令报错
解决方案 这个错误信息表明,你的系统(可能是 Windows)阻止了 PowerShell 执行脚本,这是由于 PowerShell 的执行策略导致的。PowerShell 的执行策略控制着在系统上运行哪些 PowerShell 脚本。默认情况下,Windows 可能…...
Canvas入门教程!!【Canvas篇二】
没有一朵花,从一开始就是花。 目录 translate() 方法:rotate() 方法:scale() 方法: translate() 方法: Canvas 2D API 的 CanvasRenderingContext2D.translate() 方法用于对当前网格添加平移变换。 translate() 方法通…...
windows服务器及网络:搭建FTP服务器
前言:(各位大佬们,昨天太忙了,整得没有发布昨天那该写的那一篇,属实有点可惜的说QAQ,不过问题已经解决,我又回来啦) 今天我要介绍的是在Windows中关于搭建FTP服务器的流程与方法 注…...
[4A/OP]
2.2 安装程序 2.2.1 解压缩.tar.gz文件 调用UNIX命令tar会在当前目录下创建4A/OP子例程主目录4AOP-1.5/,包括所有必要的子目录。只需键入以下命令即可解压缩和“untar”4AOP-1.5.tar.gz: tar -xzvf 4AOP-1.5.tar.gz4AOP-1.5/目录现在应该已经创建&…...
C++学习之网络攻防以及信息搜索
目录 1.课程安排 2.课程介绍 3.渗透测试 4.ptes渗透测试执行标准的介绍 5.网络攻防环境的介绍 6.kali系统的介绍和调整 7.搜索引擎踩点 8.dnsenum和nslookup 9.whois命令 10.traceroute命令 11.复习 12.traceroute原理 13.telnet命令 14.在线存货ping 15.nmap扫描…...
4.5/Q1,GBD数据库最新文章解读
文章题目:Cross-Country Inequalities in Disease Burden and Quality of Care of Stroke, 1990-2021: A Systematic Analysis of the Global Burden of Disease Study 2021 DOI:10.1111/ene.70050 中文标题:1990 年至 2021 年中风疾病负担和…...
py语法基础理解
条件判断 只有if-else等我语句,Python不支持switch语句 单if语句 if 条件语句: 条件为真时执行的内容 if-else语句 if 条件语句: 条件为真时执行的内容 else: 条件为假时执行的内容 if-elif语句 else if if 条件语句1: 条件语句1为真时执行的内容 elif 条件语句…...
python——异常
1、定义 异常是在代码执行过程中发生的,它会影响到程序的正常运行。python程序不会自动来进行异常处理。python中常见异常父类:Exception。 2、常见异常 TypeError:类型错误异常。ValueError:值的异常。KeyError:键…...
深入理解指针(4)
1.二级指针 如何理解呢? 1.pp的类型是int * * ——二级指针类型 2.p指向a,a的类型是int 3.int * * pp 其中 int * 在说明 pp 是指向 p 的类型 int * ,第二个 * 说明 pp 是指针变量 4.p 1 跳过 4 个字节 , pp 1 跳过 4 或者 8 个字节&am…...
Apipost免费版、企业版和私有化部署详解
Apipost是企业级的 API 研发协作一体化平台,为企业提供 API研发测试管理全链路解决方案,不止于API研发场景,增强企业API资产管理。 Apipost 基于同一份数据源,同时提供给后端开发、前端开发、测试人员使用的接口调试、Mock、自动化…...
小火电视桌面 TV版 老旧历史版本安装包 官方免费下载
如果你还在为小火桌面tv版无法使用而烦恼,四处寻找其他新老版本安装包,那么不妨试试乐看家桌面,它能为你带来全新的电视使用体验。 乐看家桌面的界面简洁纯净,没有繁琐的层级和恼人的广告,大字体、大图标设计ÿ…...
Java常用API详解
本文将系统讲解Java开发中高频使用的工具类API,涵盖数学计算、系统操作、对象处理和大数运算等场景。ps:本文是免费的,如果被csdn锁了,请联系我.如果需要查看更详细的说明,可以查阅javaAPI帮助文档.我本来想直接把API文档整合到文章中方便大家下载,结果csdn这货直接…...
jdk-8u202-linux-x64.tar.gz官方下载地址
https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html 点击下载,需要先注册oracle账号,很好注册随便写,注册完登录就可以下载了。目前就Oracle JDK 8u201/202 是最后两个可免费用于商业用途的公开版本...
内联函数(c++)
预处理:优点:内嵌到目标代码,减少函数的调用。 缺点:在预处理阶段完成替换,避免了语义上的差错。 egg: #define SQR(X) ((X)*(X)) 函数:优点:完成了某一类操作的抽象,…...
Python 基础语法与数据类型(四) - 布尔类型 (bool) 与逻辑运算符 (and, or, not) 和类型转换
文章目录 布尔类型 (bool)逻辑运算符 (and, or, not)布尔值的“真值”判断 (Truthiness / Falsiness)类型转换 (Type Casting)总结 在前面的文章中,我们学习了数字类型(整型、浮点型)和字符串。今天,我们要介绍另一种非常基础且极…...
WebUI可视化:第7章:系统优化与部署实战
第7章:系统优化与部署实战 学习目标 ✅ 掌握Web应用的性能优化技巧 ✅ 实现安全可靠的线上部署 ✅ 配置监控与日志系统 ✅ 了解云服务成本控制方法 7.1 性能优化策略 7.1.1 前端优化 python # 示例:Gradio异步处理 demo.queue(concurrency_count=5) # 控制并发数 de…...
79. 单词搜索
题目 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或…...
Spring @Transactional 自调用问题深度解析
Spring Transactional 自调用问题深度解析 问题本质:自调用事务失效 当类内部的方法A调用同一个类的另一个带有Transactional注解的方法B时,事务注解不会生效。这是因为Spring的事务管理是基于AOP代理实现的,而自调用会绕过代理机制。 原理…...
支付宝小程序组件与页面构造器使用指南:从页面到组件的正确迁移
引言 在支付宝小程序开发中,我们经常会遇到需要将页面组件化的情况。本文将通过一个实际案例(将 /pages/plugin/device 从页面迁移到组件),深入分析支付宝小程序中页面和组件的区别,以及正确的迁移方式。我们将从问题…...
version `GLIBCXX_3.4.32‘ not found 解决方法
环境:Ubuntu 24.04 报错:ImportError: /home/ge/opt/anaconda3/envs/roboTwin/bin/../lib/libstdc.so.6: version GLIBCXX_3.4.32 not found (required by /home/ge/Desktop/RoboTwin/third_party/pytorch3d_simplified/pytorch3d/_C.cpython-310-x86_6…...
vue3中nextTick的作用及示例
在Vue 3中,nextTick是一个用于处理DOM异步更新的工具函数,确保在数据变化后操作最新的DOM。以下是其作用的详细解析: 核心作用 延迟回调到DOM更新后:Vue的响应式系统会将数据变更批量处理,异步更新DOM。nextTick允许你…...
WHAT - 《成为技术领导者》思考题(第一章)
文章目录 思考题思路与示例框架1. 观察一位你心目中的领导者2. 若要提升自己的领导技能,你期望哪些方面得到提高?3. 如果领导技能提高,哪些生活层面可能恶化?值得吗?如何缓解?4. 列“提升他人生产效率” vs…...
今日行情明日机会——20250425
指数依然在震荡,等待方向选择,整体量能不搞但个股红多绿少。 2025年4月25日涨停板行业方向分析如下: 一、核心行业方向及驱动逻辑 一季报增长(17家涨停) 核心个股:惠而浦、鸿博股份、卫星化学驱动逻辑&am…...
数据库-子查询、关联查询 和 TCL 语言
标题目录 子查询使用场景子查询分类在 DQL 中使用子查询单行单列子查询多行单列子查询 在 DML 中使用子查询在 DDL 中使用子查询视图 关联查询关联关系的分类连接条件主外键关联N 表关联查询关联查询中使用聚合函数 TCL 语言事务的特性(ACID)在事务中控制…...
精华贴分享|【牛马课题】可转债多策略研究-1【基础篇】
本文来源于量化小论坛策略分享会板块精华帖,作者为Mc,发布于2025年3月19日。 以下为精华帖正文: 01 背景 本次牛马主题是可转债的多策略研究。在第一次牛马线上会议讨论时,我曾表达对今年转债市场的看好。 原因在于:…...
精读27页健康医疗大数据安全管控分类分级实施指南
这篇文档是一份关于健康医疗大数据安全管控分类分级实施指南的文档。该指南的主要内容包括数据分类、数据分级、数据开放形式、数据对外开放分级管控、数据模糊化与标签化、数据对外开放典型场景、数据内部分级安全管控和IS&ITS管理手册等内容。 具体来说,该指南…...
Spring MVC 数据绑定利器:深入理解 @InitBinder
在使用 Spring MVC 开发 Web 应用时,我们经常需要处理从 HTTP 请求(如 URL 参数、表单数据)到 Controller 方法参数的自动转换。这就是 Spring 的数据绑定 (Data Binding) 机制。虽然 Spring 提供了很多默认的类型转换器(比如字符…...
【HTTP/2:信息高速公路的革命】
HTTP/2:信息高速公路的革命 想象一下,如果说HTTP/1.1是一条繁忙的双向马路,那么HTTP/2就是一座现代化的高速公路网络系统,彻底改变了数据传输的方式。让我们通过生动的比喻和图表,深入了解这场网络通信的革命。 HTTP…...
PMIC PCA9450 硬件原理全解析:为 i.MX 8M 平台供电的“大脑”
在嵌入式 Linux 系统中,电源设计是构建稳定系统的基础。PCA9450 是 NXP 推出的一款高度集成的 电源管理芯片(PMIC),专为 i.MX 8M 系列处理器设计。它不仅提供多路电压输出,还具备可编程启动顺序、动态电压调节、低功耗…...
【计算机视觉】CV实战项目 - 深入解析基于HOG+SVM的行人检测系统:Pedestrian Detection
深入解析基于HOGSVM的行人检测系统:从理论到实践 技术核心:HOGSVM检测框架HOG特征原理SVM分类器 项目架构与数据准备INRIA Person数据集目录结构 实战指南:从零构建检测系统环境配置完整训练流程检测应用 关键技术问题与解决方案1. 难例挖掘不…...
巴西kwai短视频推广旅游广告获客营销策略
巴西kwai短视频平台作为一种新兴的推广渠道,可以为旅游广告带来新的营销机遇。以下是一些针对利用kwai短视频平台推广旅游广告的获客营销策略: 制作吸引人的内容:在kwai平台上发布具有吸引力的短视频内容,包括美丽的风景、当地文化…...
智慧医疗领域TMI期刊2025年3月研究热点解析
本推文对2025年3月《IEEE Transactions on Medical Imaging》(TMI)期刊论文的研究热点进行了深入分析。本期TMI涵盖了多模态图像融合、深度学习在医学诊断中的应用、三维重建与分割、图像引导治疗等关键方向,呈现出智慧医疗与人工智能深度融合…...
系统思考:看清问题背后的结构
组织的挑战,往往不是因为不努力,而是“看不清” 结束了为期两天系统思考课程的第一天,被学员的全情投入深深打动。我们用系统结构图,一步步揭示那些表面看起来“习以为常”的问题: 什么原因跨部门协作总是磕磕绊绊&am…...
计算机组成原理实验(1) 算术逻辑运算单元实验
实验一 算术逻辑运算单元实验 一、实验目的 1、掌握简单运算器的数据传输方式 2、掌握74LS181的功能和应用 二、实验内容 1、不带进位位逻辑或运算实验 2、不带进位位加法运算实验 3、实验指导书2.15实验思考 三、实验步骤和结果 实验内容一:不带进位…...
网络安全概述:定义、重要性与发展历程
网络安全概述:定义、重要性与发展历程 在互联网深度融入生活与工作的今天,网络安全已成为不可忽视的关键领域。从个人隐私泄露到企业数据失窃,再到国家关键基础设施遭受攻击,网络安全事件频发,深刻影响着个人、组织乃…...
应力腐蚀环功能及指标
西安力创(LETRY)应力腐蚀环广泛应用于高品质材料的生产检测和研究中。在H2S 作用下准确运用应力环测试可获取石油勘探,航天航空,焊接密封,海运船舶,食品加工等各类材料在各种酸,碱腐蚀环境的腐蚀…...
【多目标进化算法】常见多目标进化算法一览
算法全称核心特点备注NSGA-IINon-dominated Sorting Genetic Algorithm II非支配排序 拥挤度最经典,应用最广NSGA-IIINon-dominated Sorting Genetic Algorithm III支撑向量引导,适合高维(3目标以上)NSGA-II 的高维扩展版MOEA/DM…...
【2025 最新前沿 MCP 教程 01】模型上下文协议:AI 领域的 USB-C
文章目录 1. MCP 来了2. 什么是 MCP?为何它是颠覆性创新?M N 问题:解开 AI 集成乱麻 3. 采用 MCP 的核心优势:普适性价值MCP 与传统 API 集成的对比概览 4. 未来的路 1. MCP 来了 没想到,2025 年的每一天都在上演 「…...
抖音集团电商流量实时数仓建设实践
摘要:本文整理自抖音集团电商数据工程师姚遥老师在 Flink Forward Asia 2024 分论坛中的分享。内容主要分为五个部分: 1、业务和挑战 2、电商流量建模架构 3、电商流量流批一体 4、大流量任务调优 5、总结和展望 01.业务和挑战 第一部分给大家介绍一下流…...
redis客户端库redis++在嵌入式Linux下的交叉编译及使用
在开发过程中,我们经常会遇到需要在嵌入式Linux系统上与Redis进行交互的需求。因此选择一个适合的Redis客户端库就显得尤为重要。下面介绍下c中有名的redis-plus-plus(redis)三方库在嵌入式linux下的交叉编译及使用。该库底层是基于hiredis的…...
5.3 Dify:低代码平台,适用于企业快速部署合规AI应用
Dify作为一款开源低代码平台,已成为企业快速构建和部署合规AI应用的首选工具。Dify通过整合后端即服务(Backend-as-a-Service, BaaS)、大型语言模型操作(LLMOps)以及直观的视觉化界面,显著降低了AI应用开发…...
什么是可重入锁ReentrantLock?
大家好,我是锋哥。今天分享关于【什么是可重入锁ReentrantLock?】面试题。希望对大家有帮助; 什么是可重入锁ReentrantLock? ReentrantLock 是 Java 中的一个锁实现,它是 java.util.concurrent.locks 包中的一部分,主要用于提供…...
【Java学习日记26】:方法的重载
一、方法重载核心概念 方法重载(Overload):指在同一个类中定义多个同名方法,但这些方法的参数列表必须不同。重载的目的是让同一功能的方法能处理不同类型或数量的参数,提高代码复用性。 二、判断是否构成重载的规则 …...
分层设计数据仓库的架构和设计高效数据库系统的方法
结合你所有的知识和技术,设计一套高效的数据仓库的分层架构说明每一层分层的用途以及为什么要这么设计,有什么优势?再从数据建模和其它的角度详细论述如何设计出一个高性能的数据仓库系统? 高效数据仓库分层架构设计 分层架构及…...
铃木一郎女儿是奥运会选手吗·棒球1号位
铃木一朗(Ichiro Suzuki) 铃木一朗职业生涯时间线 1973年出生于日本爱知县名古屋市。1992年以选秀第四顺位加入日本职棒(NPB)欧力士蓝浪队,开启职业棒球生涯。 1994-2000年 连续7年获得NPB太平洋联盟打击王ÿ…...
ORB-SLAM3核心模块、数据结构和线程交互方面解析
ORB-SLAM3作为当前最先进的视觉SLAM系统之一,其代码架构设计体现了高度模块化和多线程协同的特点。以下结合代码实现和系统原理,从核心模块、数据结构和线程交互三个维度展开详细解析: 一、核心架构模块 1. 线程划分 ORB-SLAM3采用多线程架构,主要包含以下核心线程: Tra…...
小刚说C语言刷题——1565成绩(score)
1.题目描述 牛牛最近学习了 C 入门课程,这门课程的总成绩计算方法是: 总成绩作业成绩 20% 小测成绩 30% 期末考试成绩 50%。 牛牛想知道,这门课程自己最终能得到多少分。 输入 三个非负整数 A、B、C ,分别表示牛牛的作业成…...
查找函数【C++】
二分查找函数 lower_bound(起始地址, 末尾地址, target):查找第一个大于等于target目标值的位置 upper_bound(起始地址, 末尾地址, target):查找第一个大于target目标值的位置 binary_search(起始地址, 末尾地址, target):查找target是否存在…...